窗体程序是VC编写的,一个简单的用户名/密码验证:
逆向的目的很简单,找到验证用户名和密码的汇编代码段
思路一、通过注册失败字符串"registed fail"或者注册成功字符串回溯
步骤:
1、在OD CPU窗口右键选择:搜索所有应用的字符串菜单项:
2、右键选择反汇编窗口中跟随:
来到CPU视图:
选中的部分汇编代码就是验证用户名和密码的汇编代码,这只是个样例,实际中可能还需要向上成调用函数回溯查找验证入口代码
思路二、通用主线程Call Stack(调用栈)回溯实现
步骤:
1、直接在OD中运行程序,输入错误的账号密码,然后弹出错误的消息:
2、观察分析OD的调用栈视图:
这个视图上的所有过程从上之下是一种被调用关系,例如:ntdll.KiFastSystemCallRet被USER32.WaitMessage+0A调用,USER32.WaitMessage+0A再被USER32.77D277D5调用,USER32.77D277D5再被USER32.77D249BF调用,如此一直到最后被USER32.77D28E9B调用。
很明显我们当前弹出的框是靠USER32.MessageBoxW这个函数弹出的,而这个函数又被mfc100u.787A0D9F调动。我们可以双击这里或者右键选择"Show Call"回到CPU视图:
在这里按F2(下一个INT3类型的断点),在此点击注册按钮,程序在这里断下来。
现在有两种办法,你可以找到这段代码的函数入口,然后回溯,另一种是按Alt+F9程序继续执行,知道返回程序领空,当这个过程会弹出对话框,你点击确定即可立即回到程序领空。
在程序领空我们往上看,再次找到了刚才的验证代码:
思路三、要验证必然会获取界面上文本框的值:用户名和密码,故采用下API断点的方式,获取文本框的API较多,你要尝试看是哪一个,我选择的是GetWindowTextW
通过命令:bp GetWindowTextW下一个API断点,然后运行程序点击“注册”按钮,程序在端点处停下来:
接下找到函数的入口向上层回溯,可能要回溯几层函数才能找到目标,这里不赘述。
思路四、在“注册”按钮上拦截按钮消息:WM_LBUTTONUP,我觉得这个办法很不错。如何实现呢,由于Windows系统是一个消息驱动的系统,所有消息都要经过TranslateMessage这个函数,将virtual-key messages 转换为character messages,所以我们在这个函数上下条件断点:
步骤:
1、找到这个API函数:在CPU视图执行快捷键"Ctrl+G"在弹出框你输入“TranslateMessage”:
光标所在行就是TranslateMessage API函数的入口,在这里下一个条件端点:
按下Shift+F4或者右键:
在弹出界面里面输入:
选择当条件满足时(On Condition)暂停程序(Pause program),其它选项不管。
表达式说明:[[ESP+4]]==0x0130606 && [[ESP+4]+4]==WM_LBUTTONUP
0x0130606为按钮的句柄
WM_LBUTTONUP为消息类型,即鼠标左键按钮按下弹起时。
要明白 [[ESP+4]]和 [[ESP+4]+4],必须搞懂很多东西,首先是汇编方法调用的传参规则,ESP+4指向的就是传递给当前API函数TranslateMessage的参数。
下面是函数原型:
BOOL TranslateMessage( CONST MSG *lpMsg // message information );
意思是传递给该函数的是一个“消息结构的指针”,而这个消息未来是WM_LBUTTONUP类型.我们观察整个结构体:
typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG, *PMSG;这里的 HWND hwnd; UINT message; 都是4字节的。
[ESP+4] ---------->取得参数值,该参数值是指向消息结构的指针
[[ESP+4]] ---------->通过“指向消息结构的指针”取得消息结构头4个字节的内容,即hwnd,这个就是按钮句柄
[ESP+4]+4------------>“指向消息结构的指针”加4得到“指向结构体的第二个4字节的地址”,即message,我们要判断这个message是否是WM_LBUTTONUP
2、点击“注册”按钮,程序在这里断下来,按下"Alt+F9"运行,直到返回程序领空:
向上回溯,立即找到目标。
至此,4种思路罗列完毕。暂时想到这些。