160个Crackme046 (首发) Dll注入添加功能(附C++源代码)

开始拿到本题我也一脸茫然,也没有游戏说明。于是就随便看了看,发现菜单上的三个选项都提示Nope doesn’t work yet!,即这三个功能都不能用,再看看这个题目的分类是Menu,我想,这题就是要我们让这三个选项能正常使用吧,就类似于Crackme041那题,要我们加代码。开始呢,我想到的就是在结尾处添加代码,用ollydbg搜索了一下,发现很多必要的Api函数没有导入进去,手动添加又太麻烦。而且要加三个功能,汇编代码量肯定很大。于是就想起了dll注入,这个技术,我也是现学现用。它的原理是通过某种手段,让程序加载我们的dlldll中的DllMain函数就会自动执行,我们可以把一些代码放这个函数里。这种技术也应用于许多病毒程序中。

 

为什么dll注入后可以控制应用程序?

在Windows中,每个应用程序都是独立运行在自己的内存空间,有没有发现,我们用ollydbg打开exe,第一行指令的地址总是0x401000 ,程序A从这个地址开始执行,程序B也从这个地址开始执行,但是他们互不影响,即这些地址并不是物理地址,而是一个相对的地址。每个程序有独立的地址空间,自己空间里的线程可以随便操控自己的内存,那么,如果我们把自己的dll加载到程序的空间里去,这个dll就成了程序的一部分,可以操控这个程序的内存。

 

 

首先,我们来写dll注入程序,

要将dll注入到一个进程中,我们利用CreateRemoteThread在exe进程中运行LoadLibrary线程来加载指定的dll文件,在这里还要注意目标exe使用的是LoadLibraryA还是LoadLibrayW,要一致才能成功,这个坑了我好久

 

  1. //注入dll  
  2. #include <windows.h>  
  3. #include <stdio.h>  
  4. #include <TlHelp32.h>  
  5.   
  6. //根据进程名查找进程PID  
  7. DWORD getProcessHandle(LPCTSTR lpProcessName) {  
  8.     DWORD dwRet = 0;  
  9.     HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);  
  10.     if(hSnapShot == INVALID_HANDLE_VALUE) {  
  11.         printf("\n获得进程快照失败%d",GetLastError());  
  12.         return dwRet;  
  13.     }  
  14.   
  15.     PROCESSENTRY32 pe32;//声明进程入口对象  
  16.     pe32.dwSize = sizeof(PROCESSENTRY32);//填充进程入口对象大小  
  17.     Process32First(hSnapShot,&pe32);//遍历进程列表  
  18.     do {  
  19.         if(!lstrcmp(pe32.szExeFile,lpProcessName)) { //查找指定进程名的PID  
  20.             dwRet = pe32.th32ProcessID;  
  21.             break;  
  22.         }  
  23.     } while (Process32Next(hSnapShot,&pe32));  
  24.     CloseHandle(hSnapShot);  
  25.     return dwRet;//返回  
  26. }  
  27.  
  28. BOOL InjectDll(DWORD dwPID, char* szDllPath) {  
  29.     HANDLE hProcess = NULL;  
  30.     HANDLE hThread = NULL;  
  31.     HMODULE hMod = NULL;  
  32.     LPVOID pRemoteBuf = NULL; //存储dll路径字符串的起始地址  
  33.     DWORD dwBufSize = (DWORD)(strlen(szDllPath)+1)*sizeof(char); // dll路径字符串的大小  
  34.     LPTHREAD_START_ROUTINE pThreadProc; // 存储LoadLibrary函数的地址  
  35.     // 使用dwPID获取目标进程句柄  
  36.     if(!(hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID))) {  
  37.         printf("OpenProcess(%d) failed!!![%d]\n",dwPID,GetLastError());  
  38.         return FALSE;  
  39.     }  
  40.     // 在目标进程exe内存中分配szDLLName大小的内存  
  41.     pRemoteBuf = VirtualAllocEx(hProcess,NULL,dwBufSize,MEM_COMMIT,PAGE_READWRITE);  
  42.     // dll路径写入分配的内存  
  43.     WriteProcessMemory(hProcess,pRemoteBuf,szDllPath,dwBufSize,NULL);  
  44.     // 获取LoadLibraryW() API的地址  
  45.     //注意 LoadLibraryALoadLibraryW,要与exe的一样,不然不能成功  
  46.     hMod = GetModuleHandle(TEXT("kernel32.dll"));  
  47.     pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod,"LoadLibraryA");  
  48.     // 在对应的exe中运行线程  
  49.     hThread = CreateRemoteThread(hProcess,NULL,0,pThreadProc,pRemoteBuf,0,NULL);  
  50.     WaitForSingleObject(hThread,INFINITE);  
  51.     CloseHandle(hThread);  
  52.     CloseHandle(hProcess);  
  53.     return TRUE;  
  54. }  
  55. // 提权函数  
  56. BOOL EnableDebugPriv() {  
  57.     HANDLE hToken;  
  58.     LUID sedebugnameValue;  
  59.     TOKEN_PRIVILEGES tkp;  
  60.     if ( ! OpenProcessToken( GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) {  
  61.         printf("提权失败。");  
  62.         return FALSE;  
  63.     }  
  64.     if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) ) {  
  65.         CloseHandle( hToken );  
  66.         printf("提权失败。");  
  67.         return FALSE;  
  68.     }  
  69.     tkp.PrivilegeCount = 1;  
  70.     tkp.Privileges[0].Luid = sedebugnameValue;  
  71.     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //  
  72.     if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) ) {  
  73.         printf("提权失败。");  
  74.         CloseHandle( hToken );  
  75.     } else {  
  76.         printf("提权成功!");  
  77.         return TRUE;  
  78.     }  
  79.   
  80. }  
  81.   
  82. int main(int argc, char* argv[]) {  
  83.     //提权  
  84.     EnableDebugPriv();  
  85.     DWORD pid = getProcessHandle("douby.exe");  
  86.     char dll[50] = "DllInject.dll";  
  87.     if (InjectDll(pid,dll)) {  
  88.         printf("dll注入成功!\n");  
  89.     } else {  
  90.         printf("dll注入失败\n");  
  91.     }  
  92.     return 0;  
  93. }  

以上程序将DllInject.dll这个文件注入到名字为douby.exe这个进程中去

现在我们来写DllInject的代码

  1. BOOL APIENTRY DllMain(HMODULE hModule,  
  2.     DWORD  ul_reason_for_call,  
  3.     LPVOID lpReserved  
  4. )  
  5. {  
  6.     switch (ul_reason_for_call)  
  7.     {  
  8.     case DLL_PROCESS_ATTACH:  
  9.         MessageBox(NULL,"注入成功!","",MB_OK);  
  10.         break;  
  11.     case DLL_THREAD_ATTACH:  
  12.     case DLL_THREAD_DETACH:  
  13.     case DLL_PROCESS_DETACH:  
  14.         break;  
  15.     }  
  16.     return TRUE;  
  17. }  

DllMain就犹如Main函数作用一样,DllMain函数会在当程序加载完这个Dll时执行。这样,我们就可以在里面写代码

编译后,我们来测试一下。

douby.exe 是我们的目标程序,DllInject.dll是编译后的dll文件,keygen.exe是注入程序

首先,我们运行douby.exe

然后,我们运行keygen.exe将DllInject.dll注入到douby.exe的进程中去

这个弹窗来自我们在dll里写的那个MessageBox,这说明我们的dll被成功加载到douby.exe这个程序中去了。

 

既然测试成功,那么接下来,我们就可以为所欲为了,

如何在dll中访问宿主的内存呢?

我们可以用强制转换,把地址值转换成指针

比如,我们想访问0x401260处的内容,我们可以

  1. DWORD *p = (DWORD *)0x401260;  
  2. printf("%d\n",*p);  

本题,我们可以直接在dll中利用win api 完成所有功能,不用这么麻烦,

 

难点在于,如何取得控件窗口的句柄,以及如何接管菜单的事件?

首先是控件句柄的获取

FindWindow函数可以根据窗口名称获取窗口的句柄

EnumChildWindows函数可以枚举窗口中的控件,我们再判断控件的id来确定是不是我们要找的

 

我们主要是要获取编辑框的句柄,这样我们才能操作编辑器(设置文本,获取文本)

文本框的id是怎么找到的呢?

用ollydbg打开程序,

 

选择”所有模块间的调用”,CreateWindiows相关的名称,一个个点进去看看

我们发现了,这个控件带有EDIT字样,就是一个文本框,hMenu=00000001,这个值就是控件的ID ,不明白为什么的可以看看CreateWindow相关函数的定义。

  1. //获得编辑框  
  2. editor = FindDlgItem(0x1,mainWnd);  

于是上述我们就是这样获取编辑框的句柄

 

我们用SetWindowText函数给它设置测试文本,发现文本成功设置上去,说明这个就是那个编辑框的句柄了

现在,我们要做的就是如何响应Menu事件呢?

SetWindowLongPtr函数可以将窗口的WinProc消息接管到自己的函数里,于是

oriWndProc = SetWindowLongPtr(mainWnd, GWLP_WNDPROC, (LONG_PTR)WndProc);  

 

这个函数的第一个参数是窗口句柄,我们传入的是主窗口句柄

 

WndProc是我们自己定义的函数,用来处理事件

  1. //事件处理  
  2. LRESULT __stdcall WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  3. {  
  4.     switch (uMsg) {  
  5.     case WM_COMMAND:  
  6.         switch (wParam) {  
  7.         //几个菜单事件  
  8.         case 40001: //Load  
  9.             loadFile();  
  10.             return 0;  
  11.         case 40005: //Save  
  12.             saveFile();  
  13.             return 0;  
  14.         case 40003: //Exit  
  15.             exitApp();  
  16.             return 0;  
  17.         }  
  18.         break;  
  19.     }  
  20.     return CallWindowProcW((WNDPROC)oriWndProc, hWnd, uMsg, wParam, lParam);  
  21. }  

现在问题又来了,上述的几个值它们分别代表三个选项的ID,它们是怎么来的?

在汇编里应该可以算出来,但感觉有点麻烦,于是我就把wParam所有值都记录下来,点击相应的选项一次,再看看值。最终得到了它们的ID

 

好了,上述工作都做完了,我们来看看DllInject.cpp的完整代码

  1. #define _CRT_SECURE_NO_WARNINGS  
  2.   
  3. #include <iostream>  
  4. #include <windows.h>  
  5.   
  6. using std::cout;  
  7. using std::endl;  
  8.   
  9. //文本框控件  
  10. HWND editor;  
  11.   
  12. //退出程序  
  13. void exitApp() {  
  14.     ExitProcess(0);  
  15. }  
  16.   
  17. //加载文件  
  18. void loadFile() {  
  19.     OPENFILENAME ofn;  
  20.     CHAR szFile[100];  
  21.     LPCSTR INIT_PATH = ".txt";  
  22.     ZeroMemory(&ofn, sizeof(ofn));  
  23.     ofn.lStructSize = sizeof(ofn);  
  24.     ofn.hwndOwner = NULL;  
  25.     ofn.lpstrFile = szFile;  
  26.     ofn.lpstrFile[0] = '\0';  
  27.     ofn.nMaxFile = sizeof(szFile);  
  28.     ofn.lpstrFilter = INIT_PATH;  
  29.     ofn.nFilterIndex = 1;  
  30.     ofn.lpstrFileTitle = NULL;  
  31.     ofn.nMaxFileTitle = 0;  
  32.     ofn.lpstrInitialDir = NULL;  
  33.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;  
  34.     if (GetOpenFileName(&ofn)) {  
  35.         HANDLE hFile = CreateFile(ofn.lpstrFile,  
  36.             GENERIC_READ,  
  37.             0,  
  38.             NULL,  
  39.             OPEN_EXISTING,  
  40.             FILE_ATTRIBUTE_NORMAL,  
  41.             0  
  42.         );  
  43.         if (hFile == INVALID_HANDLE_VALUE)  
  44.         {  
  45.             MessageBox(NULL, "创建文件句柄出错""error", MB_OK);  
  46.             return;  
  47.         }  
  48.         DWORD size = GetFileSize(hFile,NULL);  
  49.         if (size == -1) {  
  50.             MessageBox(NULL, "获取文件大小出错""error", MB_OK);  
  51.             return;  
  52.         }  
  53.         CHAR* data = new CHAR[size];  
  54.         int filesucc = ReadFile(hFile,  
  55.             data,  
  56.             size,//读取文件中多少内容  
  57.             NULL,  
  58.             NULL  
  59.         );  
  60.         SetWindowText(editor,data);  
  61.         delete[] data;  
  62.         CloseHandle(hFile);  
  63.     }  
  64. }  
  65.   
  66. //保存文件  
  67. void saveFile() {  
  68.     OPENFILENAME ofn;  
  69.     CHAR szFile[100];  
  70.     LPCSTR TYPE = ".txt";  
  71.     ZeroMemory(&ofn, sizeof(ofn));  
  72.     ofn.lStructSize = sizeof(ofn);  
  73.     ofn.hwndOwner = NULL;  
  74.     ofn.lpstrFile = szFile;  
  75.     ofn.lpstrFile[0] = '\0';  
  76.     ofn.nMaxFile = sizeof(szFile);  
  77.     ofn.lpstrFilter = NULL;  
  78.     ofn.nFilterIndex = 1;  
  79.     ofn.lpstrFileTitle = NULL;  
  80.     ofn.nMaxFileTitle = 0;  
  81.     ofn.lpstrInitialDir = NULL;  
  82.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;  
  83.     if (GetSaveFileName(&ofn)) {  
  84.         HANDLE hFile = CreateFile(ofn.lpstrFile,  
  85.             GENERIC_WRITE,  
  86.             0,  
  87.             NULL,  
  88.             CREATE_NEW,  
  89.             FILE_ATTRIBUTE_NORMAL,  
  90.             0  
  91.         );  
  92.         if (hFile == INVALID_HANDLE_VALUE)  
  93.         {  
  94.             MessageBox(NULL, "创建文件句柄出错""error", MB_OK);  
  95.             return;  
  96.         }  
  97.         int size = GetWindowTextLengthA(editor);  
  98.         CHAR* buf = new CHAR[size];  
  99.         GetWindowText(editor,buf,size);  
  100.         DWORD dwWritenSize = 0;  
  101.         BOOL bRet = WriteFile(hFile,buf,size, &dwWritenSize, NULL);  
  102.         CloseHandle(hFile);  
  103.         delete[] buf;  
  104.         MessageBox(NULL, "文件保存成功!""ojbk", MB_OK);  
  105.     }  
  106. }  
  107.   
  108. struct StructFindTaskManagerDlgItem  
  109. {  
  110.     DWORD  itemID;//控件ID  
  111.     HWND   hwnd;//该控件的句柄  
  112. };  
  113.   
  114. //枚举子控件  
  115. BOOL CALLBACK _EnumChildProc(HWND hwnd, LPARAM lParam)  
  116. {  
  117.     StructFindTaskManagerDlgItem* pParam = (StructFindTaskManagerDlgItem*)lParam;  
  118.   
  119.     if ((DWORD)GetDlgCtrlID(hwnd) == pParam->itemID)//判断是否为需要的控件  
  120.     {  
  121.         pParam->hwnd = hwnd;  
  122.   
  123.         return FALSE;  
  124.     }  
  125.   
  126.     return TRUE;  
  127. }  
  128.   
  129. //根据控件ID获取控件控件句柄  
  130. HWND FindDlgItem(DWORD CtrlId,HWND & mainWnd)  
  131. {  
  132.     StructFindTaskManagerDlgItem param;  
  133.   
  134.     param.itemID = CtrlId;  
  135.     param.hwnd = NULL;  
  136.   
  137.     //根据窗口名字,即可获取到它的句柄  
  138.     //获取主窗口句柄  
  139.     mainWnd = FindWindow(0x0,"ReverseMe1 - Official practice of the Reverse EngineerZINE");  
  140.     if (mainWnd == NULL)  
  141.     {  
  142.         MessageBox(NULL, "请先运行douby.exe程序!""", MB_OK);  
  143.         return NULL;  
  144.     }  
  145.     //枚举子窗口,  
  146.     EnumChildWindows(mainWnd, _EnumChildProc, (LPARAM)& param);  
  147.     return param.hwnd;  
  148. }  
  149.   
  150. LONG_PTR oriWndProc;  
  151.   
  152. //事件处理  
  153. LRESULT __stdcall WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  154. {  
  155.     switch (uMsg) {  
  156.     case WM_COMMAND:  
  157.         switch (wParam) {  
  158.         //几个菜单事件  
  159.         case 40001: //Load  
  160.             loadFile();  
  161.             return 0;  
  162.         case 40005: //Save  
  163.             saveFile();  
  164.             return 0;  
  165.         case 40003: //Exit  
  166.             exitApp();  
  167.             return 0;  
  168.         }  
  169.         break;  
  170.     }  
  171.     return CallWindowProcW((WNDPROC)oriWndProc, hWnd, uMsg, wParam, lParam);  
  172. }  
  173.   
  174. HWND mainWnd;  
  175.   
  176. void Start()  
  177. {  
  178.     //为窗口设置新的事件处理  
  179.     oriWndProc = SetWindowLongPtr(mainWnd, GWLP_WNDPROC, (LONG_PTR)WndProc);  
  180. }  
  181.   
  182. //初始化一些事  
  183. void initSome() {  
  184.     //获得编辑框  
  185.     editor = FindDlgItem(0x1,mainWnd);  
  186.     //创建线程,用于接管窗口事件  
  187.     CreateThread(NULL, NULL, reinterpret_cast<LPTHREAD_START_ROUTINE>(Start), NULL, NULL, NULL); // start another thread running the hooking stuff  
  188. }  
  189.   
  190. BOOL APIENTRY DllMain(HMODULE hModule,  
  191.     DWORD  ul_reason_for_call,  
  192.     LPVOID lpReserved  
  193. )  
  194. {  
  195.     switch (ul_reason_for_call)  
  196.     {  
  197.     case DLL_PROCESS_ATTACH:  
  198.         initSome();  
  199.         MessageBox(NULL,"注入成功!","",MB_OK);  
  200.         break;  
  201.     case DLL_THREAD_ATTACH:  
  202.     case DLL_THREAD_DETACH:  
  203.     case DLL_PROCESS_DETACH:  
  204.         break;  
  205.     }  
  206.     return TRUE;  
  207. }  

    我们最终的测试结果

    测试动画
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值