文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

网络安全编程:文件补丁及内存补丁

2024-12-03 05:12

关注

微信公众号:计算机与网络安全

ID:Computer-network

有时破解一个程序后可能会将其发布,而往往被破解的程序只是修改了其中一个程序而已,无须将整个软件都进行打包再次发布,只需要发布一个补丁程序即可。发布补丁常见的有三种情况,第一种情况是直接把修改后的文件发布出去,第二种情况是发布一个文件补丁,它去修改原始的待破解的程序,最后一种情况是发布一个内存补丁,它不修改原始的文件,而是修改内存中的指定部分。

3种情况各有好处。第一种情况将已经修改后的程序发布出去,使用者只需要简单进行替换就可以了。但是有个问题,如果程序的版本较多,直接替换可能就会导致替换后的程序无法使用。第二种方法是发布文件补丁,该方法需要编写一个简单的程序去修改待破解的程序,在破解以前可以先对文件的版本进行判断,如果补丁和待破解程序的版本相同则进行破解,否则不进行破解。但是有时候修改了文件以后,程序可能无法运行,因为有的程序会对自身进行校验和比较,当校验和发生变化后,程序则无法运行。最后一种方式是内存补丁,也需要自己动手写程序,并且写好的补丁程序需要和待破解的程序放在同一个目录下,执行待破解的程序时,需要执行内存补丁程序,内存补丁程序会运行待破解的程序,然后比较补丁与程序的版本,最后进行破解。同样,如果有内存校验的话,也会导致程序无法运行。不过,无论是文件校验还是内存校验,都可以继续对被校验的部分进行打补丁来突破程序校验的部分。本文编写一个文件补丁程序和内存补丁程序。

1. 文件补丁

用OD修改CrackMe是比较容易的,如果脱离OD该如何修改呢?其实在OD中修改反汇编的指令以后,对应地,在文件中修改的是机器码。只要在文件中能定位到指令对应的机器码的位置,那么直接修改机器码就可以了。JNZ对应的机器码指令为0x75,JZ对应的机器码指令为0x74。也就是说,只要在文件中找到这个要修改的位置,用十六进制编辑器把0x75修改为0x74即可。如何能把这个内存中的地址定位到文件地址呢?这就是PE文件结构中把VA转换为FileOffset的知识了。

具体的手动步骤,请大家自己尝试,这里直接通过写代码进行修改。为了简单起见,这里使用控制台来编写,而且直接对文件进行操作,省略中间的步骤。有了思路以后,就不是难事了。

关于文件补丁的代码如下:

  1. #include  
  2. #include  
  3. int main(int argc, char* argv[]) 
  4.   // VA = 00401EA8 
  5.   // FileOffset = 00001EA8 
  6.   DWORD dwFileOffset = 0x00001EA8; 
  7.   BYTE bCode = 0; 
  8.   DWORD dwReadNum = 0; 
  9.   // 判断参数 
  10.   if ( argc != 2 ) 
  11.   { 
  12.     printf("Please input two argument \r\n"); 
  13.     return -1; 
  14.   } 
  15.   // 打开文件 
  16.   HANDLE hFile = CreateFile(argv[1], 
  17.     GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ, 
  18.     NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL); 
  19.   if ( hFile == INVALID_HANDLE_VALUE ) 
  20.   { 
  21.     return -1; 
  22.   } 
  23.   SetFilePointer(hFile, dwFileOffset, 0, FILE_BEGIN); 
  24.   ReadFile(hFile, (LPVOID)&bCode, sizeof(BYTE), &dwReadNum, NULL); 
  25.   // 比较当前位置是否为 JNZ 
  26.   if ( bCode != '\x75' ) 
  27.   { 
  28.     printf("%02X \r\n", bCode); 
  29.     CloseHandle(hFile); 
  30.     return -1; 
  31.   } 
  32.   // 修改为 JZ 
  33.   bCode = '\x74'
  34.   SetFilePointer(hFile, dwFileOffset, 0, FILE_BEGIN); 
  35.   WriteFile(hFile, (LPVOID)&bCode, sizeof(BYTE), &dwReadNum, NULL); 
  36.   printf("Write JZ is Successfully ! \r\n"); 
  37.   CloseHandle(hFile); 
  38.   // 运行 
  39.   WinExec(argv[1], SW_SHOW); 
  40.   getchar(); 
  41.   return 0; 

代码给出了详细的注释,只需要把CrackMe文件拖放到文件补丁上或者在命令行下输入命令即可,如图1所示。

 

 

 

 

图1 对CrackMe进行文件补丁

通常,在做文件补丁以前一定要对打算进行修改的位置进行比较,以免产生错误的修改。程序使用的方法是将要修改的部分读出来,看是否与用OD调试时的值相同,如果相同则打补丁。由于这里只是介绍编程知识,针对的是一个CrackMe。如果对某个软件进行了破解,自己做了一个文件补丁发布出去给别人使用,不进行相应的判断就直接进行修改,很有可能导致软件不能使用,因为对外发布以后不能确认别人所使用的软件的版本等因素。因此,在进行文件补丁时最好判断一下,或者是用CopyFile()对文件进行备份。

2. 内存补丁

相对文件补丁来说,还有一种补丁是内存补丁。这种补丁是把程序加载到内存中以后对其进行修改,也就是说,本身是不对文件进行修改的。要将CrackMe载入内存中,载入内存可以调用CreateProcess()函数来完成,这个函数参数众多,功能强大。使用CreateProcess()创建一个子进程,并且在创建的过程中将该子进程暂停,那么就可以安全地使用WriteProcessMemory()函数来对CrackMe进行修改了。整个过程也比较简单,下面直接来阅读源代码:

  1. #include  
  2. #include  
  3. int main(int argc, char* argv[]) 
  4.   // VA = 004024D8 
  5.   DWORD dwVAddress = 0x00401EA8; 
  6.   BYTE bCode = 0; 
  7.   DWORD dwReadNum = 0; 
  8.   // 判断参数数量 
  9.   if ( argc != 2 ) 
  10.   { 
  11.     printf("Please input two argument \r\n"); 
  12.     return -1; 
  13.   } 
  14.   STARTUPINFO si = { 0 }; 
  15.   si.cb = sizeof(STARTUPINFO); 
  16.   si.wShowWindow = SW_SHOW; 
  17.   si.dwFlags = STARTF_USESHOWWINDOW; 
  18.   PROCESS_INFORMATION pi = { 0 }; 
  19.   BOOL bRet = CreateProcess(argv[1], 
  20.     NULL,NULL,NULL,FALSE
  21.     CREATE_SUSPENDED, // 将子进程暂停 
  22.     NULL,NULL,&si,&pi); 
  23.   if ( bRet == FALSE ) 
  24.   { 
  25.     printf("CreateProcess Error ! \r\n"); 
  26.     return -1; 
  27.   } 
  28.   ReadProcessMemory(pi.hProcess, 
  29.     (LPVOID)dwVAddress,(LPVOID)&bCode, 
  30.     sizeof(BYTE),&dwReadNum); 
  31.   // 判断是否为 JNZ 
  32.   if ( bCode != '\x75' ) 
  33.   { 
  34.     printf("%02X \r\n", bCode); 
  35.     CloseHandle(pi.hThread); 
  36.     CloseHandle(pi.hProcess); 
  37.     return -1; 
  38.   } 
  39.   // 将 JNZ 修改为 JZ 
  40.   bCode = '\x74'
  41.   WriteProcessMemory(pi.hProcess, 
  42.     (LPVOID)dwVAddress,(LPVOID)&bCode, 
  43.     sizeof(BYTE),&dwReadNum); 
  44.   ResumeThread(pi.hThread); 
  45.   CloseHandle(pi.hThread); 
  46.   CloseHandle(pi.hProcess); 
  47.   printf("Write JZ is Successfully ! \r\n"); 
  48.   getchar(); 
  49.   return 0; 

代码中的注释也比较详细,代码的关键是要进行比较,否则会造成程序的运行崩溃。在进行内存补丁前需要将线程暂停,这样做的好处是有些情况下可能没有机会进行补丁就已经执行完需要打补丁的地方了。当打完补丁以后,再恢复线程继续运行就可以了。

参考文献:C++ 黑客编程揭秘与防范(第3版) 

 

来源:计算机与网络安全内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯