171028 逆向-以CM41为例进行Dll注入(上)

来源:互联网 发布:毕向东java视频百度云 编辑:程序博客网 时间:2024/06/06 13:12

1625-5 王子昂 总结《2017年10月28日》 【连续第393天总结】
A. CrackMe41–dll注入
B.
dll注入的原理是利用一个进程控制被注入进程执行LoadLibrary函数,将外部dll注入其内存中。注入以后由于共享内存空间,因此dll也就拥有了操作该进程内存的权限了。

当Dll被注入时会运行DllMain函数,这就是Dll的主函数。

由于之前没有写过Dll注入,因此这次准备先执行一个MessageBox作为Hook成功标志,明天再将前一次得到的成功经验照样通过dll注入来实现。

首先,Dll注入分为3个阶段:
1.外部函数控制被注入程序执行LoadLibrary函数加载外部Dll
2.Dll注入,执行DllMain函数
3.Hook住被注入程序的函数,当条件满足时触发Hook函数

依次完成,首先是外部函数:

#include <iostream>#include <windows.h>#include <tchar.h>using namespace std;BOOL InjectDll(int dwPID, LPCTSTR szDllPath){        HANDLE hProcess = NULL, hThread = NULL;        HMODULE hMod = NULL;        LPVOID pRemoteBuf = NULL;        DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);        LPTHREAD_START_ROUTINE pThreadProc;        // 获取目标进程句柄        if(!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))        {            cout<<dwPID<<endl;            cout<<"failed!!!\n";            return FALSE;        }        // 在目标进程内存中分配szDllName大小的内存        pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);        // 将myhack.dll路径写入分配的内存        WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);        // 获取LoadLibraryA地址        hMod = GetModuleHandle("kernel32.dll");        pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");        // 运行线程        hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);        //等待该线程执行完毕        WaitForSingleObject(hThread, INFINITE);        CloseHandle(hThread);        CloseHandle(hProcess);        return TRUE;}int main(int argc, TCHAR *argv[]){    if(InjectDll(atoi(argv[1]), "F:\\C\\cm41_hoook\\bin\\Debug\\cm41_hoook.dll"))        cout<<"Success "<<argv[2]<<endl;    else        cout<<"Failed"<<endl;    return 0;}

参照书上代码,main函数接收被注入程序的PID,从而执行InjectDll函数
InjectDll函数通过PID获取该进程的句柄,然后将参数(外部Dll的路径)和函数(Kernel32.dll中的LoadLibrary函数)准备好,通过CreateRemoteThread函数来控制被注入进程开启一个新线程加载dll

注意这里LoadLibrary函数取的地址事实上是注入函数的,但由于dll共享内存,因此地址可以通用

注意LoadLibrary函数的W和A,刚开始在这里犯错了OTZ
W表示宽字符,A表示ASCII,默认字符串是ASCII的,因此使用A
PID通过任务管理器可以查看到

第二步编写DllMain函数:

BOOL NewMenu(){    return (MessageBoxA(NULL, "Hook success", "Second", MB_OKCANCEL));}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)NewMenu);            break;    }    return TRUE; // succesful}

hook_by_code就是修改代码来hook的函数,NewMenu是hook目标函数
hook_by_code取得目标函数的地址作为参数,来修改代码:

BOOL hook_by_code(PROC pfnNew){    HANDLE hProcess;    DWORD* pfnOrg;    //push的机器码    byte pBuf[6] = {0x68};    DWORD oldProtect;    //Hook地址    pfnOrg = (DWORD*)0x430535;    //将hook目标函数的地址送入缓冲区中    memcpy(&pBuf[1], &pfnNew, 4);    //ret的机器码    pBuf[5] = 0xc3;    //修改内存属性为可写    VirtualProtect((LPVOID)pfnOrg, 10, PAGE_EXECUTE_READWRITE, &oldProtect);    //将缓冲区写入被注入程序的内存    memcpy(pfnOrg, pBuf, 6);    return TRUE;}

目前需要程序运行的内容为(汇编):

push 0xaaaaaaaa ;目标函数地址ret ;call 目标函数地址

刚开始执行的时候花式报错,原来是data节区没有可写属性,因此需要用VirtualProtect函数开启该权限
hook的地址还是老地方:
这里写图片描述

这样注入以后,就能实现弹窗了

这里写图片描述
查到PID以后通过命令行执行程序:
这里写图片描述
看到弹出注入成功的弹窗,说明DllMain已经开始执行,Dll成功加载入该程序中
这里写图片描述
点击二级菜单后弹出Hook成功的弹窗,说明代码成功被Hook

虽然点完确定以后就会出现内存错误的警报,但这是预料之中的—因为我们只设置了Hook,没有令它返回嘛

明天来完善Hook程序,以及正常返回~

C. 明日计划
dll注入(下)

阅读全文
0 0
原创粉丝点击