代码注入
// 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函数创建线程。
到此注入就完成了。

浙公网安备 33010602011771号