171029 逆向-以CM41为例进行Dll注入(中)
来源:互联网 发布:手机弹钢琴软件 编辑:程序博客网 时间:2024/06/06 07:53
1625-5 王子昂 总结《2017年10月29日》 【连续第394天总结】
A. CrackMe41–Dll注入(中)
B.
本次注入Dll所要注意的地方比较多
首先因为编写代码语言是C++(其实用内联汇编代码写起来费事点,但是处理乱七八糟的堆栈和参数传递要省心的多),因此要注意参数问题
其次是Hook点
Hook函数的执行次序为
Hook函数应该尽可能地降低影响,来避免内存访问错误
是否要执行原函数由具体情况决定,为了降低对原程序的影响程度,最好执行
因为原函数内可能会执行一些对其他地方有影响的操作,不止是堆栈和寄存器的操作,还有一些全局变量操作等等
代码编写起来比较简单,主要是代码的改变,和hook函数的代码
为了执行在hook函数中执行原函数,需要考虑函数指针,两种解决办法:
DLL调用exe里的函数,如果知道函数地址的话 2种方法
1 dll里用函数指针指向exe里的函数
比如exe里有个函数 int SetHook(HWND, HWND);
DLL里就这样
typedef int (CALLBACK* sthook)(HWND, HWND);
sthook SetHook;SetHook = (sthook)0x00XXXXXX;//0x00XXXXXX是 SetHook的地址
然后DLL里就能用SetHook函数了2 内联汇编
比如exe里有个函数 int SetHook(HWND, HWND); , 函数地址是0x00XXXXXX
DLL中
__asm {
push eax
mov eax, hwnd_arg2
push eax
mov eax, hwnd_arg1
push eax
mov eax, 0x00XXXXXX
call eax
add esp, 8
pop eax
}
写好代码以后原函数调用总是失败
发现原函数的参数传递是使用寄存器eax,ebx
而C++编译的函数是通过调用约定来提取参数的,存在于eax或堆栈中
也就是说C语言写的函数提不到ebx的值,即使是写在函数最顶端的内联汇编也由于编译而拿不到原始的ebx
如果Hook函数不需要判断的话,参数倒是无所谓。但是本次Hook由于需要判断被点击的按钮是否为”Exit”来决定弹窗,因此必须拿到参数
最后没办法,想到了令被Hook函数在跳转前将参数保存到全局变量中的方法
即在push func_addr; retn之前 mov par_addr, eax
然后判断par即可
调试发现dll中使用C->函数指针的方法调用函数,实际上会占用寄存器:
这样的话eax参数就不可能送进去了╮(╯_╰)╭
只能使用内联汇编的方法了
由于我使用的Code::Blocks编译器支持的是gcc格式的内联汇编,是AT&T记法,所以用起来比较麻烦
有空赶紧换VS编译器_(:з」∠)_VC格式的内联汇编(INTEL记法)才比较熟悉
asm("movl %%eax, %0\n" "movl %%ebx, %1\n" "movl %%ecx, %2\n" "call %%ecx" : :"a"(eax),"b"(ebx),"c"(hook_addr) );
这样就将之前存储在变量中的值分别送入eax,ebx,ecx中了,然后call ecx就调用了原函数
我们的目标是为Exit按钮添加事件,事件内容很简单,关键在于如何判断Exit按钮
之前静态patch时使用的方法是Hook二级菜单的事件,判断edx(控件下标),由于这次Hook的是窗体事件的函数,控件下标edx已经丢失了,所以只能思考别的办法
eax中存储的是该控件结构体的指针,因此只要在其中找到Caption即可判断按钮。内存中下断分析以后发现是0xe8的位置开始(&Exit),因此只需要判断eax+0xe9的值是否为’E’即可
Dll代码如下:
#include "main.h"#define hook_addr 0x42f3c0//mov edx, dl//push addr//retbyte pBuf[20] = {0x89, 0x5,0,0,0,0,0x89, 0x1d, 0,0,0,0, 0x68};byte OrgBytes[20];int ebx;int eax;int* ebx_p;int* eax_p;BOOL hook_by_code(PROC pfnNew){ DWORD* pfnOrg; DWORD oldProtect; pfnOrg = (DWORD*)hook_addr; ebx_p = &ebx; eax_p = &eax; memcpy(OrgBytes, pfnOrg, 18); memcpy(&pBuf[2], &eax_p, 4); memcpy(&pBuf[8], &ebx_p, 4); memcpy(&pBuf[13], &pfnNew, 4); //ret pBuf[17] = 0xc3; //修改内存属性为可写 VirtualProtect((LPVOID)pfnOrg, 10, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(pfnOrg, pBuf, 18); return TRUE;}BOOL New_42f3c0(){ /*函数指针调用方法,由于eax传参而废弃 typedef int (CALLBACK* func)(); org_func = (func)another_func_addr; func org_func; org_func(); */ DWORD* pfnOrg; org_func = (func)hook_addr; byte oldBuf[7] = {0x53, 0x8b, 0xd8, 0x80, 0x7b, 0x2d, }; pfnOrg = (DWORD*)hook_addr; //脱钩 memcpy(pfnOrg, OrgBytes, 18); //送入参数并执行原函数 asm("movl %%eax, %0\n" "movl %%ebx, %1\n" "movl %%ecx, %2\n" "call %%ecx" : :"a"(eax),"b"(ebx),"c"(hook_addr) ); //check if(*(byte*)(eax + 0xe9)=='E') if(MessageBoxA(NULL, "Do you fickbirne really want to quit?", "Exit", MB_YESNO)==6) exit(0); else ; //再次挂钩 memcpy(pfnOrg, pBuf, 18); return 0;}extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ //MessageBoxA(NULL, "Dll inject success", "First", MB_OK); switch (fdwReason) { case DLL_PROCESS_ATTACH: // attach to process // return FALSE to fail DLL load hook_by_code((PROC)New_42f3c0); break; } return TRUE; }
这样就可以通过Dll注入的方法来外部添加事件了,相比起静态Patch而言这种方法要更加灵活
如果Hook的是API的话,参数乖乖按照调用约定通过堆栈传递的话,C的代码写起来要比汇编方便许多
PS:
中间我也试过许多其他的方法,例如像静态Patch的方法一样Hook二级菜单的函数,也吃了不少教训。
例如说Hook点最好在函数开头,参数与该函数一致,这样可以尽可能地保持堆栈平衡
像静态Patch那样直接掐下来二级菜单的函数,通过id判断来执行两个事件而不执行原函数的方法对于该程序也是可以的,并且相对而言要简单不少
只不过方法来讲不是太完善,因为完全跳过了原函数,如果其中还有什么其他处理的话就会造成程序不稳定。因此标准起见,应该在Hook函数内执行原函数。
明天来继续完善这个程序,例如说可以注出Dll,还原patch;检测是否被注入过,进行错误处理,等等
C. 明日计划
Dll注入完善
- 171029 逆向-以CM41为例进行Dll注入(中)
- 171028 逆向-以CM41为例进行Dll注入(上)
- 171031 逆向-以CM41为例进行Dll注入(下)
- 171016 逆向-DLL注入基础知识
- swig--在java、C#中调用c++写的DLL(以vs2012配置为例)
- swig--在java、C#中调用c++写的DLL(以vs2012配置为例)
- DShow中filter的property page实现过程(以DsNetWork为例进行摘抄)
- DLL在跨平台之间的使用中遇到的问题(以delphi中开发的dll,在vc中使用为例)
- 171114 逆向-以CM为例学习MFC机制
- pandas和数据库进行交互(以mysql为例)
- 以杯子为例进行测试设计
- 远程线程注入技术(3)之DLL以数据形式注入
- 以mysql为例介绍PreparedStatement防止sql注入原理
- Android中利用httpclient进行网络通信的方法(以用户登录为例说明)
- 配置st_geometry.dll(以ArcGIS10.5.1+Oracle12c R1为例)
- Excel中利用VLOOKUP进行逆向查找(亲自实践)
- 171024 逆向-以Xp0int的so fun为例利用Zjdroid安卓脱壳
- 进行DLL注入的三种方法
- Spring 学习笔记(8)—— SpringMVC 简介、DispatcherServlet 配置
- FBKVOController详解
- js内存泄漏常见情况
- UDP实现linux与Windows之间数据传输
- mysql 忽略主键冲突、避免重复插入的几种方式
- 171029 逆向-以CM41为例进行Dll注入(中)
- 深度学习笔记(一)-CNN原理研究
- Android hdpi,xhdpi,xxhdpi 屏幕适配
- 大数加法
- 记录自己学习和工作中的点滴
- DigitalOcean+shadowsocks+ipv6免流校园网免流教程
- 网址URL中特殊字符转义
- 如何编辑PDF文件内容才好?这个方法你要收藏了
- AutoCompleteTextView 输入框自动提示 记录小结