《C++反汇编与逆向分析技术揭秘》学习之第18章 反汇编代码的重建与编译

发布时间:2026/7/10 22:32:48

《C++反汇编与逆向分析技术揭秘》学习之第18章 反汇编代码的重建与编译 在逆向分析的基础上如何将目标分析程序中的反汇编代码提取出来重建并编译呢本章将带领读者解决这个问题找到目标程序中的关键代码并提取出来将其编译成一个新的程序。18.1 重建反汇编代码重建反汇编代码是先将目标程序中的关键代码提取出来然后将其组建成汇编代码。有了IDA这个强大的分析工具要做到这一点非常容易。先准备好示例程序如图18-1所示。图18-1 示例程序本例是一个控制面板程序为了便于学习程序的功能非常简单只是将输入字符串中的小写字符转换成大写字符。本节的任务是将这段转换字符的代码提取出来然后组建成可编译的汇编代码。首先使用IDA打开分析文件ToUpper.exe文件在随书文件中查看功能代码所在位置如代码清单18-1所示。代码清单18-1 分析ToUpper程序IDA分析00401030 _main proc near ; main()函数入口 00401030 00401030 Text byte ptr -100h ; 局部变量以及参数标号定义 00401030 var_FF byte ptr -0FFh 00401030 argc dword ptr 4 00401030 argv dword ptr 8 00401030 envp dword ptr 0Ch 00401030 sub esp, 100h ; 局部变量空间申请 00401036 push edi 00401037 mov ecx, 3Fh 0040103C xor eax, eax 0040103E lea edi, [esp104hvar_FF] 00401042 mov [esp104hText], 0 ; 初始化数组为0 00401047 push offset aIFIOg ; 请输入字符串\n 0040104C rep stosd 0040104E stosw 00401050 stosb 00401051 call _printf 00401056 lea eax, [esp108hText] 0040105A push eax 0040105B push offset Format ; %255s 00401060 call _scanf 00401065 lea ecx, [esp110hText] 00401069 push ecx 0040106A call sub_401000 ; 转换函数 0040106F add esp, 10h 00401072 lea edx, [esp104hText] 00401076 push 0 ; uType 00401078 push offset Caption ;“转换结果” 0040107D push edx ; lpText 0040107E push 0 ; hWnd 00401080 call ds:MessageBoxA ; 部分代码分析略 0040108F _main endp笔记--------------------------------------------start笔记--------------------------------------------end通过分析代码清单18-1我们找到了要提取的代码的首地址它在地址标号sub_401000处。进入此地址进一步分析如代码清单18-2所示。代码清单18-2 sub_401000处的分析IDA分析sub_401000 proc near ; 函数入口 00401000 arg_0 dword ptr 4 ; 参数标号定义此函数只有一个参数 00401000 00401000 push esi 00401001 mov esi, [esp4arg_0] 00401005 push edi 00401006 mov edi, esi 00401008 or ecx, 0FFFFFFFFh 0040100B xor eax, eax 0040100D repne scasb 0040100F not ecx 00401011 dec ecx ; 这里是一段内联函数strlen 00401012 xor edx, edx 00401014 test ecx, ecx 00401016 jle short loc_40102D 00401018 loc_401018: ; 地址标号 00401018 mov al, [edxesi] 0040101B cmp al, 61h 0040101D jl short loc_401028 0040101F cmp al, 7Ah 00401021 jg short loc_401028 00401023 sub al, 20h 00401025 mov [edxesi], al loc_401028: ; 地址标号 00401028 inc edx 00401029 cmp edx, ecx 0040102B jl short loc_401018 loc_40102D: ; 地址标号 0040102D pop edi 0040102E pop esi 0040102F retn 0040102F sub_401000 endp笔记--------------------------------------------start笔记--------------------------------------------end代码清单18-2为小写字符转换成大写字符的实现代码因为本节要讲解的内容为反汇编代码的重建所以不再对代码清单进行深入分析。直接复制并粘贴代码清单18-2中的反汇编代码将其修改为合法的汇编代码如代码清单18-3所示。代码清单18-3 重建后的汇编代码-汇编源码.486 ; 根据代码清单18-1与代码清单18-2的分析函数的调用方式为c调用对于调用约定的 ; 判断非常重要这会直接影响程序的运行结果以及栈的平衡 .model flat, c option casemap :none .code ; 代码段定义 ToUpper proc arg_0:DWORD ; 函数入口 push esi mov esi, arg_0 ; 语法修正 push edi mov edi, esi or ecx, 0FFFFFFFFh xor eax, eax repne scasb not ecx dec ecx xor edx, edx test ecx, ecx jle short loc_40102D loc_401018: ; 地址标号 mov al, [edxesi] cmp al, 61h jl short loc_401028 cmp al, 7Ah jg short loc_401028 sub al, 20h mov [edxesi], al loc_401028: ; 地址标号 inc edx cmp edx, ecx jl short loc_401018 loc_40102D: ; 地址标号 pop edi pop esi ret ToUpper endp end代码清单18-3在代码清单18-2的基础上修正了语法错误这样一来一段简单的反汇编代码重建就完成了。读者在重建反汇编代码时应注意所分析代码的调用约定对函数的调用约定判断是重建反汇编代码的重点。一旦判断错误使用了错误的调用约定极有可能影响运行结果或破坏栈的平衡使程序无法正常运行。18.2 编译重建后的反汇编代码18.1节介绍了简单的反汇编代码的重建过程如何对提取出的反汇编代码进行编译并与VS2019中的程序进行链接呢不管是汇编编译器还是C语言编辑器在编译的过程中都会生成通用的obj格式文件有了这个共同点就可以将汇编代码与C\C代码进行联合编译。首先利用RadASM对代码清单18-3进行编译生成obj文件如图18-2所示。图18-2 生成obj文件的汇编文件使汇编文件生成对应的obj文件后将图18-2中的MyToUpper.obj文件复制到VS2019的工程目录下。在VS2019的文件视图中将复制到目录的obj文件添加到当前工程中如图18-3所示。图18-3 载入obj文件这样一来函数的实现就被加载到了当前工程中如何调用obj文件中的ToUpper函数呢需要对该函数进行声明如图18-4所示。图18-4 函数接口声明在声明的过程中需要注意函数的调用约定以及加入“extern C”的说明防止函数被名词粉碎。现在万事俱备可以调用ToUpper函数了如图18-5所示。图18-5 接口调用运行程序输入字符串得到的结果如图18-6所示。查看图18-6的显示结果是不是成功地将字符串helloworld由小写字符转换为大写字符了呢这表示从图18-1所示的程序中提取出来的代码被成功执行了。图18-6 结果显示笔记--------------------------------------------start用VS2019编译生成的obj文件MyToUpper.obj添加到项目中编译运行笔记--------------------------------------------end18.3 本章小结本章主要讲解了汇编环境和C语言环境的联合编译。读者需要具备一定的逆向分析基础否则无法定位到关键的代码处联合编译也就成了一句空话。如果觉得多个obj文件的静态编译方式不方便也可以参考对应的编译链接选项做成dll的共享编译方式。很多时候有些反汇编代码无法直接编译比如异常处理、函数的嵌套等这就需要读者先分析目标程序的功能结构然后酌情对代码做出修改使其满足当前环境。如果需要重建的代码中存在C的异常处理部分那么将异常分配过程全部照搬过来明显不合适。这种情况的处理办法有多种可以先分析异常处理中是否有关键的、不可或缺的代码如果有则修改流程使得关键代码一定被执行否则可以考虑将异常的注册函数替换为自己的异常函数或者直接去掉异常的注册和处理代码然后在上级调用函数中补充实现更优的异常处理过程。

相关新闻