선릉역 1번 출구
Code Injection 본문
code 인젝션이란?
상대방 프로세스에 독립 실행 코드를 삽입한 후 실행하는 기법임
CreateRemoteThread() API를 이용해 원격 스레드 형태로 실행해 Thread injection이라고도 부름
인젝션 대상이 되는 target.exe process에 code와 data를 삽입함
code = 스레드 프로시져 형식, data = 스레드의 파라미터로 전달함
주의해야 할 내용
DLL 인젝션의 경우 DLL을 삽입하면 DLL 안에 코드와 데이터가 모두 존재하기 때문에 코드가 정상적으로 실행됨
그러나 Code 인젝션의 경우 필요한 코드를 인젝션하는 것이기 때문에 데이터도 같이 인젝션을 해주어야 함
그래야 코드의 실행이 정상적으로 가능해짐 -> 코드 인젝션이 DLL 인젝션보다 고려해야 할 사항이 많음
그럼에도 불구하고 코드 인젝션을 사용하는 이유는?
- 메모리를 적게 차지함 (DLL에 비해 메모리를 적게 차지함)
- 흔적을 찾기가 어려움 (DLL은 해당 프로세스 메모리에 흔적을 남김)
실행 방법
codeinjection.exe PID = 파라미터 2개임
1. Main()
int main(int argc, char *argv[])
{
DWORD dwPID = 0;
if( argc != 2 )
{
printf("\n USAGE : %s <pid>\n", argv[0]);
return 1;
}
// code injection
dwPID = (DWORD)atol(argv[1]);
InjectCode(dwPID);
return 0;
}
argc의 개수가 2가 아니면 return 1을 반환
dwPID = argv[1]인 PID를 atol을 통해 Long형 데이터 타입으로 변환 //여기서 PID는 상대방 프로세스로 내가 injection하고 싶은 프로세스라고 생각하면됨
InjectCode()함수에 dwPID를 매개변수로 주어 실행시킴
2. ThreadProc() = 인젝션할 코드(스레드 함수)
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;
}
독립 실행 코드를 인젝션하는 것이기 때문에 코드와 코드에서 참조하는 데이터를 같이 인젝션하는 것이 핵심임
여기 ThreadProc함수에서는 API를 호출하지 않고 전부 스레드 파라미터로 넘어온 THREA_PARAM 구조체에서 가져다 사용하고 있음
3. InjectCode()
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)¶m, // 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;
}
InjectCode() 함수의 앞부분은 THREAD_PARAM 구조체 변수 세팅임 그 다음 API 함수 호출이 이어짐
OpenProcess()
//data: THREAD_PARAM
VirtualAllocEx()
WriteProcessMemory()
//code: ThreadProc()
VirtualAllocEx()
WriteProcessMemory()
CreateRemoteThread()
api 함수 호출 flow
상대방 프로세스에 data와 code를 각각 메모리 할당하고 인젝션 해주는 것임
마지막으로 CreateRemoteThread를 사용해 원격 스레드를 실행시킴
결론
DLL인젝션은 규모가 크고 복잡한 일을 수행할 때 사용함
Code 인젝션은 규모가 작고 간단한 일을 수행할 때 사용함
DLL 인젝션과의 차이는 VirtualAlloEx와 WriteProcessMemory임
참고 사이트
https://siveriness.tistory.com/28
코드 인젝션
DLL인젝션과의 가장 큰 차이점 DLL인젝션의 경우, DLL인젝션 기법으로 DLL을 통째로 상대방 프로세스 메모리에 삽입시키므로, 코드와 데이터가 같이 메모리에 존재하기 때문에 코드는 정상적으로
siveriness.tistory.com
https://leehahoon.tistory.com/entry/Code-Injection
'Hacking & Security > Malicious code and Reversing' 카테고리의 다른 글
Hello World! Reversing (0) | 2021.12.24 |
---|---|
Reverse Engineering (0) | 2021.12.23 |
DLL Injection (0) | 2021.12.15 |
Anti Disassembly (0) | 2021.12.15 |
Windows Message Hooking(2) (0) | 2021.12.12 |