背景知识
VC++编程知识
OD工具使用
汇编知识
功能实现
简单的互换点击功能;
将两个功能互换
效果图:
创建test程序
使用VS2017创建一个新的MFC工程命名为test,去掉默认按钮,新加两个button,分别命名test,test2。
创建添加两个新方法:
“`C++
void CtestDlg::dispaly()
{
MessageBox(L”test”);
}
void CtestDlg::dispaly1()
{
MessageBox(L”test2″);
}
void CtestDlg::OnBnClickedButton1()
{
dispaly();
}
void CtestDlg::OnBnClickedButton2()
{
dispaly1();
}
编译生成`exe`可执行文件;
## 使用OD动态调试
使用`od`打开`test.exe`;
这里需要使用`bp MessageBoxW`下断点,这里因为使用宽字符(MessageBox是在库里声明了一个宏 当你使用宽字符的时候,也就是unicode的时候,自动帮你转换使用 MessageBoxW 而当你使用窄字符的时候,会自动帮你转换到 MEssageBoxA)。
然后运行`F9`。`alt+b`查看断点:
“`text
7727FD3F | user32 | 始终 | mov edi,edi
Alt+c返回CPU汇编代码窗口;切换到test.exe程序点击test2按钮;
这个时候会自行到断点地方,注意看堆栈窗口里面的数据,如以下信息;
0017EBE4 01648053 /CALL 到 MessageBoxW 来自 test.0164804D
0017EBE8 000F07D6 |hOwner = 000F07D6 (‘test’,class=’#32770′)
0017EBEC 01C6600C |Text = “test”
0017EBF0 0067EEE0 |Title = “test”
0017EBF4 00000000 \Style = MB_OK|MB_APPLMODAL
0017EBF8 0017EDD8
0017EBFC CCCCCCCC
0017EC00 0017FA3C
0017EC04 /0017ECF0
0017EC08 |015D3ED4 返回到 test.015D3ED4 来自 test.015A1169
0017EC0C |01C6600C UNICODE “test”
0017EC10 |0067EEE0 UNICODE “test”
会发现调用来源,鼠标移动到0017EBE4 01648053 /CALL 到 MessageBoxW 来自 test.0164804D右键点击反汇编窗口中跟随,然后在该call入口按F2下断点,按alt+b切换断点界面,去掉bp MessageBoxW,按F9运行。然后,然后再次点击test2 button看是否能断下。
反复测试button,发现两个button都会断下,那么证明,两处都调用了这里,这个时候,先去掉当前断点,重新下bp MessageBoxW断点,在执行一次button会发现,堆栈窗口里面还有一个调用地址;
先跟随过去,下断点,重复上面的动作测试一下,结果发现,这里才是正确的断点。
015D3E40 /> \55 push ebp ; 这里是 test2 call
015D3E41 |. 8BEC mov ebp,esp
015D3E43 |. 81EC CC000000 sub esp,0xCC
015D3E49 |. 53 push ebx
015D3E4A |. 56 push esi
015D3E4B |. 57 push edi
015D3E4C |. 51 push ecx
015D3E4D |. 8DBD 34FFFFFF lea edi,[local.51]
015D3E53 |. B9 33000000 mov ecx,0x33
015D3E58 |. B8 CCCCCCCC mov eax,0xCCCCCCCC
015D3E5D |. F3:AB rep stos dword ptr es:[edi]
015D3E5F |. 59 pop ecx ; test.015D20AB
015D3E60 |. 894D F8 mov [local.2],ecx
015D3E63 |. 6A 00 push 0x0
015D3E65 |. 6A 00 push 0x0
015D3E67 |. 68 1860C601 push test.01C66018 ; UNICODE “test2”
015D3E6C |. 8B4D F8 mov ecx,[local.2]
015D3E6F |. E8 F5D2FCFF call test.015A1169 ; call test2
015D3E74 |. 5F pop edi ; test.015D20AB
015D3E75 |. 5E pop esi ; test.015D20AB
015D3E76 |. 5B pop ebx ; test.015D20AB
015D3E77 |. 81C4 CC000000 add esp,0xCC
015D3E7D |. 3BEC cmp ebp,esp
015D3E7F |. E8 F97EFBFF call test.0158BD7D
015D3E84 |. 8BE5 mov esp,ebp
015D3E86 |. 5D pop ebp ; test.015D20AB
015D3E87 \. C3 retn
注意:这里主要是不去分析整个流程,因为这样分析很容易掉进坑爬不出来,先用测试的方法论,撸一遍可能就省去了很多时间。
到这里先保存这个call,采用同样方法找到test button的call。
015D3EA0 /> \55 push ebp ; 这里是test call
015D3EA1 |. 8BEC mov ebp,esp
015D3EA3 |. 81EC CC000000 sub esp,0xCC
015D3EA9 |. 53 push ebx
015D3EAA |. 56 push esi
015D3EAB |. 57 push edi
015D3EAC |. 51 push ecx
015D3EAD |. 8DBD 34FFFFFF lea edi,[local.51]
015D3EB3 |. B9 33000000 mov ecx,0x33
015D3EB8 |. B8 CCCCCCCC mov eax,0xCCCCCCCC
015D3EBD |. F3:AB rep stos dword ptr es:[edi]
015D3EBF |. 59 pop ecx ; test.01648053
015D3EC0 |. 894D F8 mov [local.2],ecx
015D3EC3 |. 6A 00 push 0x0
015D3EC5 |. 6A 00 push 0x0
015D3EC7 |. 68 0C60C601 push test.01C6600C ; UNICODE “test”
015D3ECC |. 8B4D F8 mov ecx,[local.2]
015D3ECF |. E8 95D2FCFF call test.015A1169 ; call test1111
015D3ED4 |. 5F pop edi ; test.01648053
015D3ED5 |. 5E pop esi ; test.01648053
015D3ED6 |. 5B pop ebx ; test.01648053
015D3ED7 |. 81C4 CC000000 add esp,0xCC
015D3EDD |. 3BEC cmp ebp,esp
015D3EDF |. E8 997EFBFF call test.0158BD7D
015D3EE4 |. 8BE5 mov esp,ebp
015D3EE6 |. 5D pop ebp ; test.01648053
015D3EE7 \. C3 retn
这里就找到两个button功能call了,需要调换两个地方,发现如果直接call修改,需要堆栈平衡,闲麻烦,往上找找谁调用这里push ebp的地址,会发现上面有个jmp,在数据窗口上面直接跳转过去;
完成
啊哈,直接把两个地址互换一下,OK完成。记录下整个分析流程。