代码注入
// CodeInjection.cpp // reversecore@gmail.com // http://www.reversecore.com #include "windows.h" #include "stdio.h" typedef struct _THREAD_PARAM { FARPROC pFunc[2]; // LoadLibraryA(), GetProcAddress() char szBuf[4][128]; // "user32.dll", "MessageBoxA", "www.reversecore.com", "ReverseCore" } THREAD_PARAM, * PTHREAD_PARAM; typedef HMODULE(WINAPI* PFLOADLIBRARYA) ( LPCSTR lpLibFileName ); typedef FARPROC(WINAPI* PFGETPROCADDRESS) ( HMODULE hModule, LPCSTR lpProcName ); typedef int (WINAPI* PFMESSAGEBOXA) ( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType ); DWORD WINAPI ThreadProc(LPVOID lParam) { PTHREAD_PARAM pParam = (PTHREAD_PARAM)lParam; HMODULE hMod = NULL; FARPROC pFunc = NULL; // LoadLibrary() hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); // "user32.dll" if (!hMod) return 1; // GetProcAddress() pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); // "MessageBoxA" if (!pFunc) return 1; // MessageBoxA() ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK); return 0; } BOOL InjectCode(DWORD dwPID) { HMODULE hMod = NULL; THREAD_PARAM param = { 0, }; HANDLE hProcess = NULL; HANDLE hThread = NULL; LPVOID pRemoteBuf[2] = { 0, }; DWORD dwSize = 0; hMod = GetModuleHandleA("kernel32.dll"); // set THREAD_PARAM param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA"); param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress"); strcpy_s(param.szBuf[0], "user32.dll"); strcpy_s(param.szBuf[1], "MessageBoxA"); strcpy_s(param.szBuf[2], "www.reversecore.com"); strcpy_s(param.szBuf[3], "ReverseCore"); // Open Process if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, // dwDesiredAccess FALSE, // bInheritHandle dwPID))) // dwProcessId { printf("OpenProcess() fail : err_code = %d\n", GetLastError()); return FALSE; } // Allocation for THREAD_PARAM dwSize = sizeof(THREAD_PARAM); if (!(pRemoteBuf[0] = VirtualAllocEx(hProcess, // hProcess NULL, // lpAddress dwSize, // dwSize MEM_COMMIT, // flAllocationType PAGE_READWRITE))) // flProtect { printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError()); return FALSE; } if (!WriteProcessMemory(hProcess, // hProcess pRemoteBuf[0], // lpBaseAddress (LPVOID)& param, // lpBuffer dwSize, // nSize NULL)) // [out] lpNumberOfBytesWritten { printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError()); return FALSE; } // Allocation for ThreadProc() dwSize = (DWORD)InjectCode - (DWORD)ThreadProc; if (!(pRemoteBuf[1] = VirtualAllocEx(hProcess, // hProcess NULL, // lpAddress dwSize, // dwSize MEM_COMMIT, // flAllocationType PAGE_EXECUTE_READWRITE))) // flProtect { printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError()); return FALSE; } if (!WriteProcessMemory(hProcess, // hProcess pRemoteBuf[1], // lpBaseAddress (LPVOID)ThreadProc, // lpBuffer dwSize, // nSize NULL)) // [out] lpNumberOfBytesWritten { printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError()); return FALSE; } if (!(hThread = CreateRemoteThread(hProcess, // hProcess NULL, // lpThreadAttributes 0, // dwStackSize (LPTHREAD_START_ROUTINE)pRemoteBuf[1], // dwStackSize pRemoteBuf[0], // lpParameter 0, // dwCreationFlags NULL))) // lpThreadId { printf("CreateRemoteThread() fail : err_code = %d\n", GetLastError()); return FALSE; } WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hProcess); return TRUE; } BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { TOKEN_PRIVILEGES tp; HANDLE hToken; LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { printf("OpenProcessToken error: %u\n", GetLastError()); return FALSE; } if (!LookupPrivilegeValue(NULL, // lookup privilege on local system lpszPrivilege, // privilege to lookup &luid)) // receives LUID of privilege { printf("LookupPrivilegeValue error: %u\n", GetLastError()); return FALSE; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; if (bEnablePrivilege) tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; else tp.Privileges[0].Attributes = 0; // Enable the privilege or disable all privileges. if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) { printf("AdjustTokenPrivileges error: %u\n", GetLastError()); return FALSE; } if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { printf("The token does not have the specified privilege. \n"); return FALSE; } return TRUE; } int main(int argc, char* argv[]) { DWORD dwPID = 0; if (argc != 2) { printf("\n USAGE : %s <pid>\n", argv[0]); return 1; } // change privilege if (!SetPrivilege(SE_DEBUG_NAME, TRUE)) return 1; // code injection dwPID = (DWORD)atol(argv[1]); InjectCode(dwPID); return 0; }
一堆typedef是针对C语言语法的,定义了函数和结构体。
先看main函数,argc,argv上一篇DLL注入说明过。
SetPrivilege函数,是权限问题。
然后获取进程号(PID),atol是把字符串转换为长整型。
然后调用InjectCode函数,注入代码。
接下来我们看看SetPrivilege函数。
typedef struct _TOKEN_PRIVILEGES
{
ULONG PrivilegeCount; //数组元素的个数
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; //数组.类型为LUID_AND_ATTRIBUTES
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
先定义了一个结构体,此结构体原型如上。
OpenProcessToken函数就是要让进程可以更改权限。
BOOL OpenProcessToken(
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle
);
第一參数是要改动访问权限的进程句柄。(GetCurrentProcess函数可以获得当前进程的访问令牌的句柄)
第三个參数就是返回的访问令牌指针,返回一个句柄;
第二个參数指定你要进行的操作类型。如要改动令牌我们要指定第二个參数为TOKEN_ADJUST_PRIVILEGES。
LookupPrivilegeValue 函数查看系统权限的特权值,返回信息到一个LUID结构体里。
BOOL LookupPrivilegeValue(LPCTSTR lpSystemName,LPCTSTR lpName,PLUID lpLuid);
第一个参数表示所要查看的系统,本地系统直接用NULL
第二个参数表示所要查看的特权信息的名称,定义在winnt.h中。(此处在main中传进来权限参数)
第三个参数用来接收所返回的制定特权名称的信息。
函数调用成功后,信息存入第三个类型为LUID的结构体中,并且函数返回非0。
然后给tp结构体赋值。使用AdjustTokenPrivileges函数调整权限。
BOOL AdjustTokenPrivileges( HANDLE TokenHandle, // handle to token BOOL DisableAllPrivileges, // disabling option PTOKEN_PRIVILEGES NewState, // privilege information DWORD BufferLength, // size of buffer PTOKEN_PRIVILEGES PreviousState, // original state buffer PDWORD ReturnLength // required buffer size ); 第一个參数是訪问令牌的句柄。第二个參数决定是进行权限改动还是除能(Disable)全部权限;第三个參数指明要改动的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包括一个数组。数据组的每一个项指明了权限的类型和
要进行的操作;
第四个參数是结构PreviousState的长度。假设PreviousState为空,该參数应为NULL;第五个參数也是一个指向TOKEN_PRIVILEGES结构的指针,存放改动前的訪问权限的信息,可空。最后一个參数为实际PreviousState结构返回的大小。
然后我们分析InjectCode函数。
这个函数中大部分都分析过,所以主要分析一下注入过程吧。
1.设置线程参数(THREAD_PARAM)
2.获取进程句柄。
3.分配内存0。
4.在内存0中写入ThreadProc的参数。
5.分配内存1。(此处计算函数大小是用InjectCode函数起始地址减去ThreadProc函数起始地址,因为两函数紧挨,所以相减即为ThreadProc函数的大小。)
6.在内存1中写入ThreadProc函数。
7.调用CreateRemoteThread函数创建线程。
到此注入就完成了。