《逆向工程核心原理》--注入学习
Windows消息钩取
一、钩子和消息钩子
钩子,英文Hook,泛指偷看或截取信息时所用的手段或工具。
Windows操作系统向用户提供GUI,它是以事件驱动(Event Driven)方式工作。事件发生后,OS将事先定义好的消息发送给相应的应用程序,应用程序分析收到的消息后执行相应动作。以敲击键盘为例,
常规Windows消息流:
- 发生键盘输入事件,WM_KEYDOWN消息被添加到OS消息队列;
- OS判断哪个应用程序发生了事件,从OS消息队列中取出消息,添加到相应应用程序的app消息队列;
- 应用程序监视自身的消息队列,发现新添加的WM_KEYDOWN消息,调用相应的事件处理程序进行处理。
附带钩子的信息流:
- 发生键盘输入事件,WM_KEYDOWN消息被添加到OS消息队列;
- OS判断哪个应用程序发生了事件,从OS消息队列中取出消息,发送给应用程序;
- 钩子程序截取信息,对消息采取一定的动作(因钩子目的而定);
- 如钩子程序不拦截消息,消息最终传输给应用程序,此时的消息可能经过了钩子程序的修改。
DLL注入
DLL注入:向运行中的其他进程强制插入特定的DLL文件,主要是命令其他进程自行调用LoadLibrary() API,加载用户指定的DLL文件。
DLL注入与一般DLL加载的主要区别是加载的目标进程是其自身或其他进程。
DLL
DLL(Dynamic Linked Library,动态链接库),DLL被加载到进程后会自动运行DllMain函数,用户可以把想要执行的额代码放到DllMain函数,每当加载DLL时,添加的代码就会自动得到执行。利用该特性可以修复程序BUG,或向程序添加新功能
1 // CodeInject.cpp : 定义控制台应用程序的入口点。 2 // 3 4 //#include "stdafx.h" 5 #include "windows.h" 6 #include "stdio.h" 7 #include <iostream> 8 #include <cstring> 9 #include "string.h" 10 using namespace std; 11 //该结构体用于接收API和4个字符串 12 typedef struct _THREAD_PARAM { 13 FARPROC pFunc[2]; 14 char szBuf[4][128]; 15 } THREAD_PARAM, *PTHREAD_PARAM; 16 17 typedef HMODULE (WINAPI *PFLOADLIBRARYA) 18 ( 19 LPCSTR lpLibFileName 20 ); 21 22 typedef FARPROC (WINAPI *PFGETPROCADDRESS) 23 ( 24 HMODULE hModule, 25 LPCSTR lpProcName 26 ); 27 28 typedef int (WINAPI *PFMESSAGEBOXA) 29 ( 30 HWND hWnd, 31 LPCSTR lpText, 32 LPCSTR lpCaption, 33 UINT uType 34 ); 35 36 DWORD WINAPI ThreadProc(LPVOID lParam){ 37 PTHREAD_PARAM pParam = (PTHREAD_PARAM)lParam; 38 HMODULE hMod = NULL; 39 FARPROC pFunc = NULL; 40 41 //未直接调用相关API和未直接定义使用字符串,而通过THREAD_PARAM结构体以线程参数的形式传递使用 42 // LoadLibrary() 43 hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); // "user32.dll" 44 if( !hMod ){ 45 return 1; 46 } 47 48 49 // GetProcAddress() 50 pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); // "MessageBoxA" 51 if( !pFunc ){ 52 return 1; 53 } 54 55 // MessageBoxA() 56 ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK); 57 58 return 0; 59 } 60 61 BOOL InjectCode(DWORD dwPID){ 62 HMODULE hMod = NULL; 63 THREAD_PARAM param = {0,}; 64 HANDLE hProcess = NULL; 65 HANDLE hThread = NULL; 66 LPVOID pRemoteBuf[2] = {0,}; 67 DWORD dwSize = 0; 68 69 hMod = GetModuleHandleA("kernel32.dll"); 70 71 //设置THREAD_PARAM结构体 72 //加载到所有进程的kernel32.dll的地址都相同,因此从本进程获取的API与在notepad进程中获取的API地址是一样的 73 param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA"); 74 param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress"); 75 strcpy(param.szBuf[0], "user32.dll"); 76 strcpy(param.szBuf[1], "MessageBoxA"); 77 strcpy(param.szBuf[2], "代码注入 By SKI12"); 78 strcpy(param.szBuf[3], "blog.csdn.net/ski_12"); 79 80 // Open Process 81 if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, // dwDesiredAccess 82 FALSE, // bInheritHandle 83 dwPID)) ) // dwProcessId 84 { 85 printf("OpenProcess() fail : err_code = %d\n", GetLastError()); 86 return FALSE; 87 } 88 89 // Allocation for THREAD_PARAM 90 //注入数据部分到进程 91 dwSize = sizeof(THREAD_PARAM); 92 if( !(pRemoteBuf[0] = VirtualAllocEx(hProcess, // hProcess 93 NULL, // lpAddress 94 dwSize, // dwSize 95 MEM_COMMIT, // flAllocationType 96 PAGE_READWRITE)) ) // flProtect 97 { 98 printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError()); 99 return FALSE; 100 } 101 //param参数值为数据 102 if( !WriteProcessMemory(hProcess, // hProcess 103 pRemoteBuf[0], // lpBaseAddress 104 (LPVOID)¶m, // lpBuffer 105 dwSize, // nSize 106 NULL) ) // [out] lpNumberOfBytesWritten 107 { 108 printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError()); 109 return FALSE; 110 } 111 112 // Allocation for ThreadProc() 113 //注入代码部分到进程 114 dwSize = (DWORD)InjectCode - (DWORD)ThreadProc; 115 if( !(pRemoteBuf[1] = VirtualAllocEx(hProcess, // hProcess 116 NULL, // lpAddress 117 dwSize, // dwSize 118 MEM_COMMIT, // flAllocationType 119 PAGE_EXECUTE_READWRITE)) ) // flProtect 120 { 121 printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError()); 122 return FALSE; 123 } 124 //ThreadProc()函数为操作代码 125 if( !WriteProcessMemory(hProcess, // hProcess 126 pRemoteBuf[1], // lpBaseAddress 127 (LPVOID)ThreadProc, // lpBuffer 128 dwSize, // nSize 129 NULL) ) // [out] lpNumberOfBytesWritten 130 { 131 printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError()); 132 return FALSE; 133 } 134 135 //将数据与代码注入到进程内存后,调用CreateRemoteThread()执行远程线程 136 if( !(hThread = CreateRemoteThread(hProcess, // hProcess 137 NULL, // lpThreadAttributes 138 0, // dwStackSize 139 (LPTHREAD_START_ROUTINE)pRemoteBuf[1], // dwStackSize 140 pRemoteBuf[0], // lpParameter 141 0, // dwCreationFlags 142 NULL)) ) // lpThreadId 143 { 144 printf("CreateRemoteThread() fail : err_code = %d\n", GetLastError()); 145 return FALSE; 146 } 147 148 WaitForSingleObject(hThread, INFINITE); 149 150 CloseHandle(hThread); 151 CloseHandle(hProcess); 152 153 return TRUE; 154 } 155 156 BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { 157 TOKEN_PRIVILEGES tp; 158 HANDLE hToken; 159 LUID luid; 160 161 if( !OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) ){ 162 printf("OpenProcessToken error: %u\n", GetLastError()); 163 return FALSE; 164 } 165 166 if( !LookupPrivilegeValue(NULL, // lookup privilege on local system 167 lpszPrivilege, // privilege to lookup 168 &luid) ) // receives LUID of privilege 169 { 170 printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 171 return FALSE; 172 } 173 174 tp.PrivilegeCount = 1; 175 tp.Privileges[0].Luid = luid; 176 if( bEnablePrivilege ) 177 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 178 else 179 tp.Privileges[0].Attributes = 0; 180 181 // Enable the privilege or disable all privileges. 182 if( !AdjustTokenPrivileges(hToken, 183 FALSE, 184 &tp, 185 sizeof(TOKEN_PRIVILEGES), 186 (PTOKEN_PRIVILEGES) NULL, 187 (PDWORD) NULL) ) 188 { 189 printf("AdjustTokenPrivileges error: %u\n", GetLastError() ); 190 return FALSE; 191 } 192 193 if( GetLastError() == ERROR_NOT_ALL_ASSIGNED ){ 194 printf("The token does not have the specified privilege. \n"); 195 return FALSE; 196 } 197 198 return TRUE; 199 } 200 201 int main(int argc, char* argv[]){ 202 DWORD dwPID = 0; 203 if( argc != 2 ){ 204 printf("\n USAGE : %s <pid>\n", argv[0]); 205 return 1; 206 } 207 208 // change privilege 209 if( !SetPrivilege(SE_DEBUG_NAME, TRUE) ){ 210 return 1; 211 } 212 213 // code injection 214 //将字符串转换为长整型 215 dwPID = (DWORD)atol(argv[1]); 216 InjectCode(dwPID); 217 218 return 0; 219 } 220
待续。。。