x32dbg/x64dbg逆向之反向分析还原c语言代码3

发布时间:2026/9/24 8:52:00
x32dbg/x64dbg逆向之反向分析还原c语言代码3 x32dbg/x64dbg逆向之反向分析还原c语言代码31) 反向分析还原c语言函数代码3还是一样哦温故而知新复习一下学到新知识上节课第二个自定义函数地址为7FF69FCF122600007FF69FCF17B9 | E8 68FAFFFF | call project1.7FF69FCF1226 | 注意他自己调用自己了递归参数在经过一系列操作会发生改变计算公式是0xE8(开辟空间)-0x20(修正值)0x10(2个Push)0x08(返回地址)0xE0release优化的优点变态但是不要急能发现规律那就是代码会变但硬编码的字符串内容绝对不会变。神奇计算公式当咱们不确定某个值是多少时候咱们可以把rax看成未知数x。所以 x 2x 3x。数组特性连续宽度一致这段汇编代码是标准的数组取值ss:[rbp4]取出来用movsxd指令把这个32位的数字符号扩展拉伸成64位的rax00007FF6CC3A1830 | 48:6345 04 | movsxd rax,dword ptr ss:[rbp4] | FileName.cpp:37, rax:__enc$textbss$end5A这里不是很理解数组取值00007FF6CC3A1834 | 48:8B8D 00010000 | mov rcx,qword ptr ss:[rbp100] | 第二和参数确认了这个就是第一个参数了获取数组的首地址最终内存地址 数组首地址(rcx) 下标(rax) × 每个元素的大小(4字节)00007FF6CC3A183B | 8B0C81 | mov ecx,dword ptr ds:[rcxrax*4] | 真正去数组里拿值00007FF6CC3A183E | E8 CAF9FFFF | call project1.7FF6CC3A120D | 调用咱们另一个自定义函数咱们看下代码还原有哪些内容分析过程分析函数参数分析局部变量分析全局变量分析函数功能分析返回值最后还原c代码这一个星期课程咱们都是把汇编给反向还原到C语言哦坚持一下咱们从简单一点的代码然后再深一点一点还原咱们写的各种exe应用2汇编代码exe文件下载请从这里下载分别有DebugRelease两个版本。请自己反编译完成代码还原就好。https://download.csdn.net/download/Strategic__/93160031Debug版本 main如果找不到请参考逆向基础的第二课“x32dbg/x64dbg逆向之找main入口方式” 00007FF6E9361BC0 | 40:55 | push rbp | FileName.cpp:73 00007FF6E9361BC2 | 57 | push rdi | 00007FF6E9361BC3 | 48:81EC C8010000 | sub rsp,1C8 | 00007FF6E9361BCA | 48:8D6C24 20 | lea rbp,qword ptr ss:[rsp20] | 00007FF6E9361BCF | 48:8D7C24 20 | lea rdi,qword ptr ss:[rsp20] | 00007FF6E9361BD4 | B9 3A000000 | mov ecx,3A | 3A:: 00007FF6E9361BD9 | B8 CCCCCCCC | mov eax,CCCCCCCC | 00007FF6E9361BDE | F3:AB | rep stosd | 00007FF6E9361BE0 | 48:8B05 59B40000 | mov rax,qword ptr ds:[__security_cookie] | rax:__enc$textbss$end55 00007FF6E9361BE7 | 48:33C5 | xor rax,rbp | rax:__enc$textbss$end55 00007FF6E9361BEA | 48:8985 98010000 | mov qword ptr ss:[rbp198],rax | rax:__enc$textbss$end55 00007FF6E9361BF1 | 48:8D0D 10040100 | lea rcx,qword ptr ds:[__14F49BB1_FileNamecpp] | FileName.cpp:15732480 00007FF6E9361BF8 | E8 AAF7FFFF | call project1.7FF6E93613A7 | 00007FF6E9361BFD | 90 | nop | 上面常规操作哦 00007FF6E9361BFE | C745 08 03000000 | mov dword ptr ss:[rbp8],3 | FileName.cpp:74看到这个记住不是说前女友是数组连续性等宽 00007FF6E9361C05 | C745 0C 09000000 | mov dword ptr ss:[rbpC],9 | 09:\t 00007FF6E9361C0C | C745 10 01000000 | mov dword ptr ss:[rbp10],1 | 00007FF6E9361C13 | C745 14 08000000 | mov dword ptr ss:[rbp14],8 | 00007FF6E9361C1A | C745 18 04000000 | mov dword ptr ss:[rbp18],4 | 00007FF6E9361C21 | C745 1C 07000000 | mov dword ptr ss:[rbp1C],7 | 00007FF6E9361C28 | C745 20 02000000 | mov dword ptr ss:[rbp20],2 | 00007FF6E9361C2F | C745 24 05000000 | mov dword ptr ss:[rbp24],5 | 00007FF6E9361C36 | C745 28 09000000 | mov dword ptr ss:[rbp28],9 | 09:\t 00007FF6E9361C3D | C745 2C 06000000 | mov dword ptr ss:[rbp2C],6 | 00007FF6E9361C44 | 4C:8D4D 64 | lea r9,qword ptr ss:[rbp64] | FileName.cpp:77, r9:__enc$textbss$end55这两个不知道是什么局部变量没赋值 00007FF6E9361C48 | 4C:8D45 44 | lea r8,qword ptr ss:[rbp44] | 那咱们就把它全部设为 0 00007FF6E9361C4C | BA 0A000000 | mov edx,A | 0A:\n写死的10应该是宏定义 #define 00007FF6E9361C51 | 48:8D4D 08 | lea rcx,qword ptr ss:[rbp8] | 获取数组的首地址 00007FF6E9361C55 | E8 07F7FFFF | call project1.7FF6E9361361 | 开始第一个自定义函数 00007FF6E9361C5A | 90 | nop | 00007FF6E9361C5B | 44:8B45 64 | mov r8d,dword ptr ss:[rbp64] | FileName.cpp:78打印咱们传递的两个参数 00007FF6E9361C5F | 8B55 44 | mov edx,dword ptr ss:[rbp44] | 通过字符串咱们可以确定他们变量名min和max 00007FF6E9361C62 | 48:8D0D D7900000 | lea rcx,qword ptr ds:[max%d min%d\n...] | 00007FF6E936AD40:max%d min%d\n 00007FF6E9361C69 | E8 E5F5FFFF | call project1.7FF6E9361253 | 00007FF6E9361C6E | 90 | nop | 00007FF6E9361C6F | BA 0A000000 | mov edx,A | FileName.cpp:80, 0A:\n宏定义 size 10 00007FF6E9361C74 | 48:8D4D 08 | lea rcx,qword ptr ss:[rbp8] | 数组的首地址 00007FF6E9361C78 | E8 50F4FFFF | call project1.7FF6E93610CD | 调用第二个自定义函数 00007FF6E9361C7D | 90 | nop | 00007FF6E9361C7E | 48:8D0D D3900000 | lea rcx,qword ptr ds:[Sorted array: ...] | FileName.cpp:81, 00007FF6E936AD58:Sorted array: 00007FF6E9361C85 | E8 C9F5FFFF | call project1.7FF6E9361253 | 同过字符串可以确定是数组的排序操作 00007FF6E9361C8A | 90 | nop | 00007FF6E9361C8B | C785 84000000 00000000 | mov dword ptr ss:[rbp84],0 | FileName.cpp:82局部变量赋值 00007FF6E9361C95 | EB 0E | jmp project1.7FF6E9361CA5 | 直接跳转到7FF6E9361CA5 00007FF6E9361C97 | 8B85 84000000 | mov eax,dword ptr ss:[rbp84] | i 00007FF6E9361C9D | FFC0 | inc eax | i 00007FF6E9361C9F | 8985 84000000 | mov dword ptr ss:[rbp84],eax | 00007FF6E9361CA5 | 83BD 84000000 0A | cmp dword ptr ss:[rbp84],A | 0A:\n可以确定这里是把sort后的数组进行打印 00007FF6E9361CAC | 7D 1A | jge project1.7FF6E9361CC8 | 大于等于跳出循环 00007FF6E9361CAE | 48:6385 84000000 | movsxd rax,dword ptr ss:[rbp84] | FileName.cpp:83, rax:__enc$textbss$end55获取i的值扩展 00007FF6E9361CB5 | 8B5485 08 | mov edx,dword ptr ss:[rbprax*48] | 最终内存地址 数组首地址(rbx)下标(rax)×元素的大小偏移 00007FF6E9361CB9 | 48:8D0D AC900000 | lea rcx,qword ptr ds:[%d ...] | 00007FF6E936AD6C:%d 00007FF6E9361CC0 | E8 8EF5FFFF | call project1.7FF6E9361253 | printf 00007FF6E9361CC5 | 90 | nop | 00007FF6E9361CC6 | EB CF | jmp project1.7FF6E9361C97 | 00007FF6E9361CC8 | BA 0A000000 | mov edx,A | FileName.cpp:85, 0A:\n宏定义 10 00007FF6E9361CCD | 48:8D4D 08 | lea rcx,qword ptr ss:[rbp8] | 获取数组首地址 00007FF6E9361CD1 | E8 A7F3FFFF | call project1.7FF6E936107D | 调用第三个自定义函数 00007FF6E9361CD6 | 8985 A4000000 | mov dword ptr ss:[rbpA4],eax | 00007FF6E9361CDC | 48:8D0D 8D900000 | lea rcx,qword ptr ds:[\nDeduplicated array: ...] | FileName.cpp:86, 00007FF6E936AD70:\nDeduplicated array: 00007FF6E9361CE3 | E8 6BF5FFFF | call project1.7FF6E9361253 | printf 00007FF6E9361CE8 | 90 | nop | 00007FF6E9361CE9 | C785 C4000000 00000000 | mov dword ptr ss:[rbpC4],0 | FileName.cpp:87下面又是一个for同样的原理就不多聊了 00007FF6E9361CF3 | EB 0E | jmp project1.7FF6E9361D03 | 00007FF6E9361CF5 | 8B85 C4000000 | mov eax,dword ptr ss:[rbpC4] | 00007FF6E9361CFB | FFC0 | inc eax | 00007FF6E9361CFD | 8985 C4000000 | mov dword ptr ss:[rbpC4],eax | 00007FF6E9361D03 | 8B85 A4000000 | mov eax,dword ptr ss:[rbpA4] | 00007FF6E9361D09 | 3985 C4000000 | cmp dword ptr ss:[rbpC4],eax | 00007FF6E9361D0F | 7D 1A | jge project1.7FF6E9361D2B | 00007FF6E9361D11 | 48:6385 C4000000 | movsxd rax,dword ptr ss:[rbpC4] | FileName.cpp:88, rax:__enc$textbss$end55 00007FF6E9361D18 | 8B5485 08 | mov edx,dword ptr ss:[rbprax*48] | 00007FF6E9361D1C | 48:8D0D 49900000 | lea rcx,qword ptr ds:[%d ...] | 00007FF6E936AD6C:%d 00007FF6E9361D23 | E8 2BF5FFFF | call project1.7FF6E9361253 | 00007FF6E9361D28 | 90 | nop | 00007FF6E9361D29 | EB CA | jmp project1.7FF6E9361CF5 | 00007FF6E9361D2B | 33C0 | xor eax,eax | FileName.cpp:90 00007FF6E9361D2D | 8BF8 | mov edi,eax | FileName.cpp:91 00007FF6E9361D2F | 48:8D4D E0 | lea rcx,qword ptr ss:[rbp-20] | 00007FF6E9361D33 | 48:8D15 C68F0000 | lea rdx,qword ptr ds:[7FF6E936AD00] | rdx:__enc$textbss$end55 00007FF6E9361D3A | E8 25F3FFFF | call project1.7FF6E9361064 | 00007FF6E9361D3F | 8BC7 | mov eax,edi | 00007FF6E9361D41 | 48:8B8D 98010000 | mov rcx,qword ptr ss:[rbp198] | 00007FF6E9361D48 | 48:33CD | xor rcx,rbp | 00007FF6E9361D4B | E8 32F3FFFF | call project1.7FF6E9361082 | 00007FF6E9361D50 | 48:8DA5 A8010000 | lea rsp,qword ptr ss:[rbp1A8] | 00007FF6E9361D57 | 5F | pop rdi | 00007FF6E9361D58 | 5D | pop rbp | 00007FF6E9361D59 | C3 | ret | 发现第一个自定义函数 0x108(开辟空间)-0x20(修正值)0x10(2个Push)0x08(返回地址)0x100 00007FF6E93619B0 | 4C:894C24 20 | mov qword ptr ss:[rsp20],r9 | FileName.cpp:13, [rsp20]:__scrt_release_startup_lockD获取参数临时保存 00007FF6E93619B5 | 4C:894424 18 | mov qword ptr ss:[rsp18],r8 | 00007FF6E93619BA | 895424 10 | mov dword ptr ss:[rsp10],edx | 00007FF6E93619BE | 48:894C24 08 | mov qword ptr ss:[rsp8],rcx | 00007FF6E93619C3 | 55 | push rbp | 00007FF6E93619C4 | 57 | push rdi | 00007FF6E93619C5 | 48:81EC 08010000 | sub rsp,108 | 00007FF6E93619CC | 48:8D6C24 20 | lea rbp,qword ptr ss:[rsp20] | [rsp20]:__scrt_release_startup_lockD 00007FF6E93619D1 | 48:8D0D 30060100 | lea rcx,qword ptr ds:[__14F49BB1_FileNamecpp] | FileName.cpp:15732480 00007FF6E93619D8 | E8 CAF9FFFF | call project1.7FF6E93613A7 | 00007FF6E93619DD | 90 | nop | 00007FF6E93619DE | B8 04000000 | mov eax,4 | FileName.cpp:14eax 4 00007FF6E93619E3 | 48:6BC0 00 | imul rax,rax,0 | rax 4 * 0 00007FF6E93619E7 | 48:8B8D 10010000 | mov rcx,qword ptr ss:[rbp110] | 某个参数的值 00007FF6E93619EE | 48:8B95 00010000 | mov rdx,qword ptr ss:[rbp100] | 某个参数的值arr 00007FF6E93619F5 | 8B0402 | mov eax,dword ptr ds:[rdxrax] | 咱们现在可以确定一个东西了数组[0] 00007FF6E93619F8 | 8901 | mov dword ptr ds:[rcx],eax | 某个参数 数组[0] 00007FF6E93619FA | B8 04000000 | mov eax,4 | FileName.cpp:15下面同样操作通过字符串咱们可以确定这里是为min,max 初始值为arr[0] 00007FF6E93619FF | 48:6BC0 00 | imul rax,rax,0 | 00007FF6E9361A03 | 48:8B8D 18010000 | mov rcx,qword ptr ss:[rbp118] | 00007FF6E9361A0A | 48:8B95 00010000 | mov rdx,qword ptr ss:[rbp100] | arr 00007FF6E9361A11 | 8B0402 | mov eax,dword ptr ds:[rdxrax] | 00007FF6E9361A14 | 8901 | mov dword ptr ds:[rcx],eax | 00007FF6E9361A16 | C745 04 01000000 | mov dword ptr ss:[rbp4],1 | FileName.cpp:16既然是min和max比较那肯定有个for循环加上下面jmp可以确定了i 1 00007FF6E9361A1D | EB 08 | jmp project1.7FF6E9361A27 | 00007FF6E9361A1F | 8B45 04 | mov eax,dword ptr ss:[rbp4] | 00007FF6E9361A22 | FFC0 | inc eax | 00007FF6E9361A24 | 8945 04 | mov dword ptr ss:[rbp4],eax | 00007FF6E9361A27 | 8B85 08010000 | mov eax,dword ptr ss:[rbp108] | 咱们输入的参数数组长度 n 00007FF6E9361A2D | 3945 04 | cmp dword ptr ss:[rbp4],eax | 和咱们输入的参数比较 00007FF6E9361A30 | 7D 62 | jge project1.7FF6E9361A94 | 大于等于跳出循环 00007FF6E9361A32 | 48:6345 04 | movsxd rax,dword ptr ss:[rbp4] | FileName.cpp:18看到下面这的操作需要知道这就是数组取值获取rbp4扩展到64 00007FF6E9361A36 | 48:8B8D 00010000 | mov rcx,qword ptr ss:[rbp100] | arr 00007FF6E9361A3D | 48:8B95 10010000 | mov rdx,qword ptr ss:[rbp110] | 00007FF6E9361A44 | 8B12 | mov edx,dword ptr ds:[rdx] | rdx:C:\\Users\\admin\\Desktop\\x64\\Debug\\Project1.exe 00007FF6E9361A46 | 391481 | cmp dword ptr ds:[rcxrax*4],edx | arr[i] 00007FF6E9361A49 | 7E 17 | jle project1.7FF6E9361A62 | arr[i] 00007FF6E9361A4B | 48:6345 04 | movsxd rax,dword ptr ss:[rbp4] | FileName.cpp:19 00007FF6E9361A4F | 48:8B8D 10010000 | mov rcx,qword ptr ss:[rbp110] | 00007FF6E9361A56 | 48:8B95 00010000 | mov rdx,qword ptr ss:[rbp100] | 00007FF6E9361A5D | 8B0482 | mov eax,dword ptr ds:[rdxrax*4] | arr[i] 00007FF6E9361A60 | 8901 | mov dword ptr ds:[rcx],eax | 把数组值给max 00007FF6E9361A62 | 48:6345 04 | movsxd rax,dword ptr ss:[rbp4] | FileName.cpp:20下面几乎一样 00007FF6E9361A66 | 48:8B8D 00010000 | mov rcx,qword ptr ss:[rbp100] | 那就可以确定是两个if了if (arr mix)和 if (arr max)如果成立赋值新的数据 00007FF6E9361A6D | 48:8B95 18010000 | mov rdx,qword ptr ss:[rbp118] | 00007FF6E9361A74 | 8B12 | mov edx,dword ptr ds:[rdx] | rdx:C:\\Users\\admin\\Desktop\\x64\\Debug\\Project1.exe 00007FF6E9361A76 | 391481 | cmp dword ptr ds:[rcxrax*4],edx | 00007FF6E9361A79 | 7D 17 | jge project1.7FF6E9361A92 | 00007FF6E9361A7B | 48:6345 04 | movsxd rax,dword ptr ss:[rbp4] | FileName.cpp:21 00007FF6E9361A7F | 48:8B8D 18010000 | mov rcx,qword ptr ss:[rbp118] | 00007FF6E9361A86 | 48:8B95 00010000 | mov rdx,qword ptr ss:[rbp100] | 00007FF6E9361A8D | 8B0482 | mov eax,dword ptr ds:[rdxrax*4] | 00007FF6E9361A90 | 8901 | mov dword ptr ds:[rcx],eax | 00007FF6E9361A92 | EB 8B | jmp project1.7FF6E9361A1F | FileName.cpp:22 00007FF6E9361A94 | 48:8DA5 E8000000 | lea rsp,qword ptr ss:[rbpE8] | FileName.cpp:23 00007FF6E9361A9B | 5F | pop rdi | 00007FF6E9361A9C | 5D | pop rbp | 00007FF6E9361A9D | C3 | ret | 发现第二个自定义函数 第二个函数咱们看名字就知道是个排序算法至于是冒泡快排二叉红黑咱们还需要进一步去确认一下 0x148(开辟空间)-0x20(修正值)0x10(2个Push)0x08(返回地址)0x140 00007FF6E9361780 | 895424 10 | mov dword ptr ss:[rsp10],edx | FileName.cpp:31一样哦先提前保存好参数 00007FF6E9361784 | 48:894C24 08 | mov qword ptr ss:[rsp8],rcx | [rsp08]:invoke_main39 00007FF6E9361789 | 55 | push rbp | 00007FF6E936178A | 57 | push rdi | 00007FF6E936178B | 48:81EC 48010000 | sub rsp,148 | 开辟 0x148空间 00007FF6E9361792 | 48:8D6C24 20 | lea rbp,qword ptr ss:[rsp20] | 00007FF6E9361797 | 48:8D0D 6A080100 | lea rcx,qword ptr ds:[__14F49BB1_FileNamecpp] | FileName.cpp:15732480 00007FF6E936179E | E8 04FCFFFF | call project1.7FF6E93613A7 | 00007FF6E93617A3 | 90 | nop | 00007FF6E93617A4 | C745 04 00000000 | mov dword ptr ss:[rbp4],0 | FileName.cpp:32三行汇编一起理解可以去确定是循环虽然有区别 00007FF6E93617AB | EB 08 | jmp project1.7FF6E93617B5 | 直接跳转 00007FF6E93617AD | 8B45 04 | mov eax,dword ptr ss:[rbp4] | i 0 00007FF6E93617B0 | FFC0 | inc eax | i 00007FF6E93617B2 | 8945 04 | mov dword ptr ss:[rbp4],eax | i 00007FF6E93617B5 | 8B85 48010000 | mov eax,dword ptr ss:[rbp148] | 某个参数 00007FF6E93617BB | FFC8 | dec eax | 某个参数 - 1 00007FF6E93617BD | 3945 04 | cmp dword ptr ss:[rbp4],eax | 开始比较 00007FF6E93617C0 | 0F8D 97000000 | jge project1.7FF6E936185D | 大于等于 00007FF6E93617C6 | C745 24 00000000 | mov dword ptr ss:[rbp24],0 | FileName.cpp:34上面理解以后可以确定下面也是循环 00007FF6E93617CD | EB 08 | jmp project1.7FF6E93617D7 | 00007FF6E93617CF | 8B45 24 | mov eax,dword ptr ss:[rbp24] | 00007FF6E93617D2 | FFC0 | inc eax | 00007FF6E93617D4 | 8945 24 | mov dword ptr ss:[rbp24],eax | 00007FF6E93617D7 | 8B45 04 | mov eax,dword ptr ss:[rbp4] | 00007FF6E93617DA | 8B8D 48010000 | mov ecx,dword ptr ss:[rbp148] | 00007FF6E93617E0 | 2BC8 | sub ecx,eax | 00007FF6E93617E2 | 8BC1 | mov eax,ecx | 00007FF6E93617E4 | FFC8 | dec eax | 00007FF6E93617E6 | 3945 24 | cmp dword ptr ss:[rbp24],eax | 00007FF6E93617E9 | 7D 6D | jge project1.7FF6E9361858 | 00007FF6E93617EB | 48:6345 24 | movsxd rax,dword ptr ss:[rbp24] | FileName.cpp:36符号扩展为64位 00007FF6E93617EF | 8B4D 24 | mov ecx,dword ptr ss:[rbp24] | j 00007FF6E93617F2 | FFC1 | inc ecx | j 1 00007FF6E93617F4 | 48:63C9 | movsxd rcx,ecx | 00007FF6E93617F7 | 48:8B95 40010000 | mov rdx,qword ptr ss:[rbp140] | 通过下面可以确定140是arr 00007FF6E93617FE | 4C:8B85 40010000 | mov r8,qword ptr ss:[rbp140] | 00007FF6E9361805 | 41:8B0C88 | mov ecx,dword ptr ds:[r8rcx*4] | arr[j 1] 00007FF6E9361809 | 390C82 | cmp dword ptr ds:[rdxrax*4],ecx | 既然是数组可以确定了arr[j] 和 arr[j 1] 比较 00007FF6E936180C | 7E 45 | jle project1.7FF6E9361853 | 如果 arr[j] arr[j 1]跳出内层循环 00007FF6E936180E | 48:6345 24 | movsxd rax,dword ptr ss:[rbp24] | FileName.cpp:38既然是两个数组比较大概率就是交换或者赋值操作了rax j 00007FF6E9361812 | 48:8B8D 40010000 | mov rcx,qword ptr ss:[rbp140] | rcx arr 00007FF6E9361819 | 8B0481 | mov eax,dword ptr ds:[rcxrax*4] | eax arr[j] 00007FF6E936181C | 8945 44 | mov dword ptr ss:[rbp44],eax | 前面没看到这个值那咱们想把它想成某个变量吧temp 00007FF6E936181F | 8B45 24 | mov eax,dword ptr ss:[rbp24] | FileName.cpp:39 eax j 00007FF6E9361822 | FFC0 | inc eax | eax j 1 00007FF6E9361824 | 48:98 | cdqe | 扩展为64位 (rax j 1) 00007FF6E9361826 | 48:634D 24 | movsxd rcx,dword ptr ss:[rbp24] | rcx j 00007FF6E936182A | 48:8B95 40010000 | mov rdx,qword ptr ss:[rbp140] | arr 00007FF6E9361831 | 4C:8B85 40010000 | mov r8,qword ptr ss:[rbp140] | 00007FF6E9361838 | 41:8B0480 | mov eax,dword ptr ds:[r8rax*4] | arr[j 1]通过上面一些列操作可以知道 00007FF6E936183C | 89048A | mov dword ptr ds:[rdxrcx*4],eax | arr[j] arr[j 1] 00007FF6E936183F | 8B45 24 | mov eax,dword ptr ss:[rbp24] | FileName.cpp:40 00007FF6E9361842 | FFC0 | inc eax | 00007FF6E9361844 | 48:98 | cdqe | 00007FF6E9361846 | 48:8B8D 40010000 | mov rcx,qword ptr ss:[rbp140] | 00007FF6E936184D | 8B55 44 | mov edx,dword ptr ss:[rbp44] | 咱们看到了临时变量。edx temp 00007FF6E9361850 | 891481 | mov dword ptr ds:[rcxrax*4],edx | arr[j 1] temp 00007FF6E9361853 | E9 77FFFFFF | jmp project1.7FF6E93617CF | FileName.cpp:42 00007FF6E9361858 | E9 50FFFFFF | jmp project1.7FF6E93617AD | FileName.cpp:43 00007FF6E936185D | 48:8DA5 28010000 | lea rsp,qword ptr ss:[rbp128] | FileName.cpp:44 00007FF6E9361864 | 5F | pop rdi | 00007FF6E9361865 | 5D | pop rbp | 00007FF6E9361866 | C3 | ret | 发现第三个自定义函数 通过下面分析咱们可以确定了也是数组操作具体是什么数组操作请自己还原哦 0x168(开辟空间)-0x20(修正值)0x10(2个Push)0x08(返回地址)0x160 00007FF6E93618A0 | 895424 10 | mov dword ptr ss:[rsp10],edx | FileName.cpp:53保存好参数防止后面操作找不到在通过公式来获取 00007FF6E93618A4 | 48:894C24 08 | mov qword ptr ss:[rsp8],rcx | 00007FF6E93618A9 | 55 | push rbp | 00007FF6E93618AA | 57 | push rdi | 00007FF6E93618AB | 48:81EC 68010000 | sub rsp,168 | 00007FF6E93618B2 | 48:8D6C24 20 | lea rbp,qword ptr ss:[rsp20] | [rsp20]:_initterm58 00007FF6E93618B7 | 48:8D0D 4A070100 | lea rcx,qword ptr ds:[__14F49BB1_FileNamecpp] | FileName.cpp:15732480 00007FF6E93618BE | E8 E4FAFFFF | call project1.7FF6E93613A7 | 00007FF6E93618C3 | 90 | nop | 00007FF6E93618C4 | C745 04 01000000 | mov dword ptr ss:[rbp4],1 | FileName.cpp:54两个局部变量赋值为1 00007FF6E93618CB | C745 24 01000000 | mov dword ptr ss:[rbp24],1 | FileName.cpp:55然后下面跟着jmp和cmp可以确定第一个循环了 00007FF6E93618D2 | EB 08 | jmp project1.7FF6E93618DC | 00007FF6E93618D4 | 8B45 24 | mov eax,dword ptr ss:[rbp24] | i 00007FF6E93618D7 | FFC0 | inc eax | i 00007FF6E93618D9 | 8945 24 | mov dword ptr ss:[rbp24],eax | 赋值回去自增结果 00007FF6E93618DC | 8B85 68010000 | mov eax,dword ptr ss:[rbp168] | 某个参数重新赋值给eax 00007FF6E93618E2 | 3945 24 | cmp dword ptr ss:[rbp24],eax | 比较 00007FF6E93618E5 | 7D 7A | jge project1.7FF6E9361961 | 大于等于跳到函数结尾 00007FF6E93618E7 | C745 44 01000000 | mov dword ptr ss:[rbp44],1 | FileName.cpp:57又是两个局部变量和上面一样可以确定了两层循环 00007FF6E93618EE | C745 64 00000000 | mov dword ptr ss:[rbp64],0 | FileName.cpp:58int temp 1 ; for (j;j;j) 00007FF6E93618F5 | EB 08 | jmp project1.7FF6E93618FF | 00007FF6E93618F7 | 8B45 64 | mov eax,dword ptr ss:[rbp64] | j 00007FF6E93618FA | FFC0 | inc eax | j 00007FF6E93618FC | 8945 64 | mov dword ptr ss:[rbp64],eax | 和上面操作一样 00007FF6E93618FF | 8B45 04 | mov eax,dword ptr ss:[rbp4] | 00007FF6E9361902 | 3945 64 | cmp dword ptr ss:[rbp64],eax | 00007FF6E9361905 | 7D 2A | jge project1.7FF6E9361931 | 00007FF6E9361907 | 48:6345 24 | movsxd rax,dword ptr ss:[rbp24] | FileName.cpp:60看到这个要知道是符号扩展64位加上参数可以确定160是arr 00007FF6E936190B | 48:634D 64 | movsxd rcx,dword ptr ss:[rbp64] | 00007FF6E936190F | 48:8B95 60010000 | mov rdx,qword ptr ss:[rbp160] | 00007FF6E9361916 | 4C:8B85 60010000 | mov r8,qword ptr ss:[rbp160] | 00007FF6E936191D | 41:8B0C88 | mov ecx,dword ptr ds:[r8rcx*4] | 00007FF6E9361921 | 390C82 | cmp dword ptr ds:[rdxrax*4],ecx | arr[i] arr[j] 00007FF6E9361924 | 75 09 | jne project1.7FF6E936192F | 如果不等于跳出当前循环继续下轮检测 00007FF6E9361926 | C745 44 00000000 | mov dword ptr ss:[rbp44],0 | FileName.cpp:62注意看某个临时变量赋值为0了之前的值 temp 1 现在的值 temp 0 00007FF6E936192D | EB 02 | jmp project1.7FF6E9361931 | FileName.cpp:63 00007FF6E936192F | EB C6 | jmp project1.7FF6E93618F7 | FileName.cpp:65 00007FF6E9361931 | 837D 44 00 | cmp dword ptr ss:[rbp44],0 | FileName.cpp:66如果temp 0 00007FF6E9361935 | 74 25 | je project1.7FF6E936195C | 如果等于0跳出循环 00007FF6E9361937 | 48:6345 24 | movsxd rax,dword ptr ss:[rbp24] | FileName.cpp:67上面理解以后下面应该很好理解了 00007FF6E936193B | 48:634D 04 | movsxd rcx,dword ptr ss:[rbp4] | 00007FF6E936193F | 48:8B95 60010000 | mov rdx,qword ptr ss:[rbp160] | 00007FF6E9361946 | 4C:8B85 60010000 | mov r8,qword ptr ss:[rbp160] | 00007FF6E936194D | 41:8B0480 | mov eax,dword ptr ds:[r8rax*4] | 00007FF6E9361951 | 89048A | mov dword ptr ds:[rdxrcx*4],eax | arr[第一个局部变量] arr[i] 00007FF6E9361954 | 8B45 04 | mov eax,dword ptr ss:[rbp4] | 00007FF6E9361957 | FFC0 | inc eax | 00007FF6E9361959 | 8945 04 | mov dword ptr ss:[rbp4],eax | 00007FF6E936195C | E9 73FFFFFF | jmp project1.7FF6E93618D4 | FileName.cpp:68 00007FF6E9361961 | 8B45 04 | mov eax,dword ptr ss:[rbp4] | FileName.cpp:69 00007FF6E9361964 | 48:8DA5 48010000 | lea rsp,qword ptr ss:[rbp148] | FileName.cpp:70 00007FF6E936196B | 5F | pop rdi | 00007FF6E936196C | 5D | pop rbp | 00007FF6E936196D | C3 | ret | Release版本 优化的不成样了不再使用rbp寄存器做修正。直接用 rsp 偏移。 00007FF6C4C411E0 | 48:895C24 08 | mov qword ptr ss:[rsp8],rbx | FileName.cpp:73,保存旧的rbx寄存器 00007FF6C4C411E5 | 57 | push rdi | 00007FF6C4C411E6 | 48:83EC 50 | sub rsp,50 | 开辟空间 00007FF6C4C411EA | 48:8B05 0F2E0000 | mov rax,qword ptr ds:[__security_cookie] | rax:mainCRTStartup防溢出Cookie 00007FF6C4C411F1 | 48:33C4 | xor rax,rsp | rax:mainCRTStartup 00007FF6C4C411F4 | 48:894424 48 | mov qword ptr ss:[rsp48],rax | rax:mainCRTStartup 00007FF6C4C411F9 | 66:0F6F05 4F200000 | movdqa xmm0,xmmword ptr ds:[__xmm00000008000000010000000900000003 | FileName.cpp:74看到这个可以取得有个数组[3, 9, 1, 8, 4, 7, 2, 5,按照之前学习应该还有几个一会找一下]; 00007FF6C4C41201 | 48:8D0D F81F0000 | lea rcx,qword ptr ds:[max%d min%d\n...] | FileName.cpp:78, 00007FF6C4C43200:max%d min%d\n 00007FF6C4C41208 | 66:0F6F0D 30200000 | movdqa xmm1,xmmword ptr ds:[__xmm00000005000000020000000700000004 | 00007FF6C4C41210 | BA 09000000 | mov edx,9 | 09:\t这些写死的值应该是编译器提前算好的了 00007FF6C4C41215 | 41:B8 01000000 | mov r8d,1 | 00007FF6C4C4121B | C74424 40 09000000 | mov dword ptr ss:[rsp40],9 | 09:\t这里应该就是剩下的两个数组元素了 【3, 9, 1, 8, 4, 7, 2, 5, 9, 6】 00007FF6C4C41223 | F3:0F7F4424 20 | movdqu xmmword ptr ss:[rsp20],xmm0 | 00007FF6C4C41229 | C74424 44 06000000 | mov dword ptr ss:[rsp44],6 | 00007FF6C4C41231 | F3:0F7F4C24 30 | movdqu xmmword ptr ss:[rsp30],xmm1 | 00007FF6C4C41237 | E8 D4FDFFFF | call project1.printf | 然后直接printf大于max和min 00007FF6C4C4123C | 45:33D2 | xor r10d,r10d | 这个应该就是第二个函数开始了 00007FF6C4C4123F | 90 | nop | 00007FF6C4C41240 | 41:B9 09000000 | mov r9d,9 | FileName.cpp:80, 09:\t某个参数 9 00007FF6C4C41246 | 33C0 | xor eax,eax | FileName.cpp:77eax 0 00007FF6C4C41248 | 45:2BCA | sub r9d,r10d | FileName.cpp:809 - 0 00007FF6C4C4124B | 45:85C9 | test r9d,r9d | 0 00007FF6C4C4124E | 7E 1E | jle project1.7FF6C4C4126E | 00007FF6C4C41250 | 8B5484 24 | mov edx,dword ptr ss:[rsprax*424] | edx arr[j 1] 00007FF6C4C41254 | 44:8B4484 20 | mov r8d,dword ptr ss:[rsprax*420] | r8d arr[j] 00007FF6C4C41259 | 44:3BC2 | cmp r8d,edx | 比较 arr[j] 和 arr[j 1] 00007FF6C4C4125C | 7E 09 | jle project1.7FF6C4C41267 | 如果成立不交换跳去j 00007FF6C4C4125E | 895484 20 | mov dword ptr ss:[rsprax*420],edx | 这里应该就是交换逻辑了 00007FF6C4C41262 | 44:894484 24 | mov dword ptr ss:[rsprax*424],r8d | 00007FF6C4C41267 | FFC0 | inc eax | 00007FF6C4C41269 | 41:3BC1 | cmp eax,r9d | 00007FF6C4C4126C | 7C E2 | jl project1.7FF6C4C41250 | 00007FF6C4C4126E | 41:FFC2 | inc r10d | 00007FF6C4C41271 | 41:83FA 09 | cmp r10d,9 | 09:\t 00007FF6C4C41275 | 7C C9 | jl project1.7FF6C4C41240 | 00007FF6C4C41277 | 48:8D0D 921F0000 | lea rcx,qword ptr ds:[Sorted array: ...] | FileName.cpp:81, 00007FF6C4C43210:Sorted array: 00007FF6C4C4127E | E8 8DFDFFFF | call project1.printf | 打印就好 00007FF6C4C41283 | 33DB | xor ebx,ebx | ebx 0 00007FF6C4C41285 | 666666:0F1F8400 00000000 | nop word ptr ds:[raxrax],ax | 空指令 00007FF6C4C41290 | 8B549C 20 | mov edx,dword ptr ss:[rsprbx*420] | FileName.cpp:83 arr[ebx] 00007FF6C4C41294 | 48:8D0D 851F0000 | lea rcx,qword ptr ds:[%d ...] | 00007FF6C4C43220:%d 00007FF6C4C4129B | E8 70FDFFFF | call project1.printf | 开始打印 00007FF6C4C412A0 | 48:FFC3 | inc rbx | rbx 00007FF6C4C412A3 | 48:83FB 0A | cmp rbx,A | 0A:\n比较10 00007FF6C4C412A7 | 75 E7 | jne project1.7FF6C4C41290 | 如果没有到10 继续上面操作 00007FF6C4C412A9 | 48:8D4C24 20 | lea rcx,qword ptr ss:[rsp20] | FileName.cpp:85 00007FF6C4C412AE | E8 BDFDFFFF | call project1.int __cdecl deduplicate(int *, int) | 下面是另一个函数 00007FF6C4C412B3 | 48:8D0D 6E1F0000 | lea rcx,qword ptr ds:[\nDeduplicated array: ...] | FileName.cpp:86, 00007FF6C4C43228:\nDeduplicated array: 00007FF6C4C412BA | 8BF8 | mov edi,eax | 00007FF6C4C412BC | E8 4FFDFFFF | call project1.printf | 00007FF6C4C412C1 | 33DB | xor ebx,ebx | 00007FF6C4C412C3 | 85FF | test edi,edi | FileName.cpp:87 00007FF6C4C412C5 | 7E 1F | jle project1.7FF6C4C412E6 | 00007FF6C4C412C7 | 66:0F1F8400 00000000 | nop word ptr ds:[raxrax],ax | 00007FF6C4C412D0 | 8B549C 20 | mov edx,dword ptr ss:[rsprbx*420] | FileName.cpp:88 00007FF6C4C412D4 | 48:8D0D 451F0000 | lea rcx,qword ptr ds:[%d ...] | 00007FF6C4C43220:%d 00007FF6C4C412DB | E8 30FDFFFF | call project1.printf | 00007FF6C4C412E0 | FFC3 | inc ebx | 00007FF6C4C412E2 | 3BDF | cmp ebx,edi | 00007FF6C4C412E4 | 7C EA | jl project1.7FF6C4C412D0 | 00007FF6C4C412E6 | 33C0 | xor eax,eax | FileName.cpp:91 00007FF6C4C412E8 | 48:8B4C24 48 | mov rcx,qword ptr ss:[rsp48] | 00007FF6C4C412ED | 48:33CC | xor rcx,rsp | 00007FF6C4C412F0 | E8 1B000000 | call project1.__security_check_cookie | 00007FF6C4C412F5 | 48:8B5C24 60 | mov rbx,qword ptr ss:[rsp60] | 00007FF6C4C412FA | 48:83C4 50 | add rsp,50 | 00007FF6C4C412FE | 5F | pop rdi | 00007FF6C4C412FF | C3 | ret |3还原的C语言代码咱们会带着各位简单过一遍哦关键部分会标注好剩下部分请自己逆向分析并还原成C语言考虑到一些初学者还是不很理解下面是部分伪代码和说明实际代码不写哦Release版本优化很多地方如果Release不好理解可以参考Debug版本的汇编进行代码还原操作。通过上面的汇编分析咱们可以知道这几个点有三个函数void test(四个参数有三个指针变量){}void test1(俩个参数有一个指针变量){}void test2(俩个参数有一个指针变量){}main(){}反向分析C语言代码可以在这里自行下载哦前提你自己实现过一遍了大部分都是过去帮国外客户授课指导教学时候给的内容如果接触过国外计算机相关的内容应该知道CSAssignmentCITS2002-SIFSCOMP 3350-Computer Organization and Assembly Language等等。正向咱们写的够多了吧这1年各种汇编c/c那如果反正来呢把某个语言下写的功能用其他语言来实现很多人叫代码还原代码互换咱们用自己的话来理解一下代码还原是从汇编反向推导出程序原本的c/c逻辑想要完整还原一模一样的源码其实很难实现特别release大量优化的时候但咱们做逆向重点不是拿源码而是吃透整套软件实现流程就行。原因很简单咱们只要吃透了软件整体逻辑和各个功能的底层原理咱们完全能用任意编程语言重新实现相同功能就算只用汇编也能单独复刻程序里某一个模块。咱们日常开发无非就是CRUD各种业务各种功能各种算法各种数据结构各种网络通信各种第三方库调用WinAPI调用各种加密各种模块各种新的开发框架各种套路对吧https://download.csdn.net/download/Strategic__/93160029

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询