首页 > 系统相关 >6.3 应用动态内存补丁

6.3 应用动态内存补丁

时间:2023-09-21 09:23:22浏览次数:42  
标签:补丁 6.3 内存 动态内存 0x90 进程 BYTE pi Size

动态内存补丁可以理解为在程序运行时动态地修改程序的内存,在某些时候某些应用程序会带壳运行,而此类程序的机器码只有在内存中被展开时才可以被修改,而想要修改此类应用程序动态补丁将是一个不错的选择,动态补丁的原理是通过CreateProcess函数传递CREATE_SUSPENDED将程序运行起来并暂停,此时程序会在内存中被解码,当程序被解码后我们则可以通过内存读写实现对特定区域的动态补丁。

当读者需要手动拉起一个进程时则可以使用OpenExeFile函数实现,该函数调用后会拉起一个进程,并默认暂停在程序入口处,返回一个PROCESS_INFORMATION结构信息;

// 打开进程并暂停运行
PROCESS_INFORMATION OpenExeFile(char *szFileName)
{
    STARTUPINFO si = { 0 };
    PROCESS_INFORMATION pi = { 0 };

    si.cb = sizeof(STARTUPINFO);
    si.wShowWindow = SW_SHOW;
    si.dwFlags = STARTF_USESHOWWINDOW;

    // 创建子线程并默认暂停
    BOOL bRet = CreateProcess(szFileName, 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi);
    if (bRet == FALSE)
    {
        exit(0);
    }
    ResumeThread(pi.hThread);
    return pi;
}

其中CreateProcess函数的一般格式:

BOOL WINAPI CreateProcess(
  LPCWSTR lpApplicationName,
  LPWSTR lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInheritHandles,
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCWSTR lpCurrentDirectory,
  LPSTARTUPINFOW lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

下面是函数的参数说明:

  • lpApplicationName:指向一个空字符结束的字符串,指定将要执行的可执行文件的名称。如果lpApplicationNameNULL,那么应该将可执行文件的名称包含在lpCommandLine所指向的字符串中。
  • lpCommandLine:指向一个空字符结束的字符串,该字符串包含了要执行的命令行和参数,用于指定要运行的可执行文件和要传递给该进程的命令行参数。
  • lpProcessAttributes:指向PROCESS_ATTRIBUTES结构体,用于指定新进程的安全描述符。
  • lpThreadAttributes:指向THREAD_ATTRIBUTES结构体,用于指定新进程的主线程的安全描述符。
  • bInheritHandles:一个布尔值,指定新进程是否继承了它的父进程的句柄。
  • dwCreationFlags:指定新进程的创建标志。一般情况下会指定为 0。
  • lpEnvironment:指向一个环境块,用于指定新进程的环境块。如果为NULL,则新进程将继承调用进程的环境块。
  • lpCurrentDirectory:指向一个空字符结束的字符串,该字符串指定新进程的当前工作目录。如果为NULL,则新进程将继承父进程的当前工作目录。
  • lpStartupInfo:指向STARTUPINFO结构体,该结构体指定了新进程的主窗口外观。
  • lpProcessInformation:指向PROCESS_INFORMATION结构体,该结构体返回了新进程的信息,例如新进程的进程标识符和主线程标识符等。

CreateProcess 函数返回一个布尔值,表示函数的调用是否成功。如果成功,则返回值为非零,否则返回值为零,并通过调用GetLastError函数获取错误代码。为了使得新进程与父进程独立运行,一般需要用到独立的进程空间和线程,这通常需要在创建新进程之前调用一些Windows系统API函数,如VirtualAlloc、CreateThread等。

接着来看封装过的三个内存读写函数,其中ReadMemory()用于读取进程内存数据,WriteMemory()用于写入内存数据,CheckMemory()则用于验证两个内存空间内的字节是否匹配。

// 读取指定的内存地址
BYTE * ReadMemory(PROCESS_INFORMATION pi, DWORD dwVAddress, int Size)
{
    BYTE bCode = 0;
    BYTE *buffer = new BYTE[Size];

    for (int x = 0; x < Size; x++)
    {
        ReadProcessMemory(pi.hProcess, (LPVOID)dwVAddress, (LPVOID)&bCode, sizeof(BYTE), 0);
        buffer[x] = bCode;
        dwVAddress++;
    }
    return buffer;
}

// 写入内存特征
BOOL WriteMemory(PROCESS_INFORMATION pi, DWORD dwVAddress, unsigned char *ShellCode, int Size)
{
    BYTE *Buff = new BYTE[Size];

    SuspendThread(pi.hThread);
    memset(Buff, *ShellCode, Size);
    VirtualProtectEx(pi.hProcess, (LPVOID)dwVAddress, Size, 0x40, 0);
    BOOL Ret = WriteProcessMemory(pi.hProcess, (LPVOID)dwVAddress, Buff, Size, 0);
    if (Ret != 0)
    {
        ResumeThread(pi.hThread);
        return TRUE;
    }
    return FALSE;
}

// 比较内存中前几个字节是否一致
BOOL CheckMemory(PROCESS_INFORMATION pi, DWORD dwVAddress, BYTE OldCode[], int Size)
{
    BYTE *Buff = new BYTE[Size];
    ReadProcessMemory(pi.hProcess, (LPVOID)dwVAddress, Buff, Size, 0);

    if (!memcmp(Buff, OldCode, Size))
    {
        /*
        for (int x = 0; x < Size; x++)
        {
            printf("内存地址: %x --> 对比地址: %x \n", Buff[x], OldCode[x]);
        }
        */
        return TRUE;
    }
    return FALSE;
}

接下来我们将通过使用特征码定位技术来实现对特定内存区域的定位并实现特征替换,首先我们搜索0x85, 0xed, 0x57, 0x74, 0x07这段特征值,并定位到0x0402507内存区域,如下图所示;

当定位到内存区域后,我们首先通过ReadMemory读取前五个字节的内存,并调用CheckMemory函数用于验证此片内存区域是否时我们需要修改的,如果验证一致则通过调用WriteMemory函数向该内存中写出替换一段0x90, 0x90, 0x90, 0x90, 0x90的指令,最后通过调用ResumeThread恢复线程运行,并以此实现动态内存补丁;

int main(int argc, char *argv[])
{
    // 动态加载进程
    PROCESS_INFORMATION pi = OpenExeFile("d://lyshark.exe");

    // 开始搜索特征码
    char ScanOpCode[5] = { 0x85, 0xed, 0x57, 0x74, 0x07 };

    // 依次传入开始地址,结束地址,特征码,以及特征码长度
    ULONG Address = ScanMemorySignatureCode(pi.dwProcessId, 0x401000, 0x47FFFF, ScanOpCode, 5);
    printf("[*] 找到内存地址 = 0x%x \n", Address);

    // 读取位于Address地址处的5条机器指令
    BYTE *recv_buffer = ReadMemory(pi, Address, 5);
    for (int x = 0; x < 5; x++)
    {
        printf("%x ", recv_buffer[x]);
    }
    printf("\n");

    // 比较Address内存中前5个字节是否一致
    BYTE cmp_code[] = { 0x85, 0xed, 0x57, 0x74, 0x07 };
    BOOL ret = CheckMemory(pi, Address, cmp_code, 5);
    if (ret == TRUE)
    {
        printf("[*] 内存一致,可以进行打补丁 \n");
    }
    else
    {
        printf("[-] 不一致 \n");
    }

    // 写入修补文件
    unsigned char set_buffer[] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
    WriteMemory(pi, Address, set_buffer, 5);

    // 运行修补后的程序
    ResumeThread(pi.hThread);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    system("pause");
    return 0;
}

当调用成功后,读者可自行跳转到0x0402507处的内存区域,观察替换效果,当替换成功后,其内存输出效果如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/fe53d98c.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

标签:补丁,6.3,内存,动态内存,0x90,进程,BYTE,pi,Size
From: https://www.cnblogs.com/LyShark/p/17719083.html

相关文章

  • 动态内存分配(callco,realloc,笔试题目)2
    相比于malloc加了有一个自动初始化的功能intmain(){ int*p=(int*)calloc(10,sizeof(int));//创建之后就默认数据初始化为0 if(p==NULL) { printf("%s\n",strerror(errno)); } else { inti=0; for(i=0;i<10;i++) { *(p+i)=i; } for(i......
  • Vm虚拟机安装 黑苹果系统(提供获取最新版本的下载渠道): 免费版本:如 12.6.3 付费版本:ma
    目录一:安装系统环境相关程序下载1、系统安装包iso下载地址:2、Mac虚拟机插件下载地址:3、vm虚拟机安装二、Vm安装黑苹果虚拟机系统1、运行环境:2、安装过程解锁工具3、创建虚拟机4、修改Mac的虚拟机的配置信息5、安装苹果虚拟机系统 正文一:安装系统环境相关程序下载1、系统安......
  • 动态内存分配(malloc,free)1
    使用动态内存开辟函数,可以创捷长度可变的数组大小,这样可以减少空间的浪费。在创建可变长度的数组时,其实在C99标准下,是可以直接创建的,例如linux下gcc编译器可以通过编译命令gcctest.c-std=c99,来实现。在vs下是不支持的,所以需要通过内存开辟函数来进行创建。在开辟空间的时候,有可能......
  • Docker+harbor+rancher2.6.3部署springboot项目
    1、在pom的文件中添加以下配置<build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>com.spotify</groupId><artifactId>docker-maven-plugin</artifactId......
  • opatch报补丁时,oui-patch.xml (Permission denied)报错
    前言一套19.19RAC环境,使用opatch工具安装数据库补丁,第一个节点成功安装,但在第二个节点执行opatch命令时报错。主要的错误有提示:/u01/app/oraInventory/ContentsXML/oui-patch.xml(Permissiondenied),具体如下所示。[grid@19crac235074478]$$ORACLE_HOME/OPatch/opatcha......
  • 编译Linux 2.6.34内核
    编译准备编译环境:Ubuntu14.04GCC版本:4.8.4编译的内核版本:Linux2.6.34内核源码下载:https://mirrors.edge.kernel.org/pub/linux/kernel/编译过程解压源码linux-2.6.34.tar.gz,进入源码目录执行以下命令:#makemrproper#makeclean#makeconfig#make>/dev/null编译......
  • PDF 补丁丁 1.0 正式版
    经过了一年多的测试和完善,PDF补丁丁发布第一个开放源代码的正式版本了。PDF补丁丁也是国内首先开放源代码、带有修改和阅读PDF的功能的 PDF处理程序之一。源代码网址:https://github.com/wmjordan/PDFPatcher软件简介及下载连接。 新增功能:第一个开放源代码版本。修......
  • DEV++6.3 中文乱码配置 方法来源网上。
    DEV++6.3中文乱码配置不显示注释问题菜单栏》工具》编辑器属性》显示》编辑器字体口<ID27071translationmissing>去掉勾选。方法1菜单栏》工具》编译器选项》编译器(编译时加入以下命令✔)命令为:-fexec-charset=gbk菜单栏》工具》编辑器属性》基本》编辑器选项》NewDocum......
  • git不同分支同步代码,打patch补丁
    背景介绍一个代码管理者,不可避免的就是要将别人修改的代码同步到其他分支或其他仓库分支,因为不是所有人都有权限去合并的。合并代码有很多方式,比如直接文件夹覆盖、文件覆盖等。但上面的方法,繁琐还容易出错。写shell脚本也可以实现。这里主要想说,可以把内核打补丁的方法,......
  • 在VirtualBox中的CentOS 6.3下安装VirtualBox增强包
    在VirtualBox中的CentOS6.3下安装VirtualBox增强包 在VirtualBox中安装好客户操作系统(GuestOS)之后,建议安装VirtualBox增强包(VirtualBoxGuestAddition),它的作用是对GuestOS的性能和可用性进行优化(也就是提高GuestOS的性能和提升使用者的使用体验)。 ......