Programming2007. 1. 13. 01:07
1. Loader의 동작

1-1. 프로세스를 생성하고 타켓이 되는 프로그램을 실행하여야 합니다. 이를 위해 사용되는 API가 CreateProcess 입니다.


MSDN에 나와있는 CreateProcess API를 살펴보면 다음과 같습니다 :
BOOL CreateProcess(
LPCTSTR lpApplicationName, // pointer to name of executable module
LPTSTR lpCommandLine, // pointer to command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes
BOOL bInheritHandles, // handle inheritance flag
DWORD dwCreationFlags, // creation flags
LPVOID lpEnvironment, // pointer to new environment block
LPCTSTR lpCurrentDirectory, // pointer to current directory name
LPSTARTUPINFO lpStartupInfo, // pointer to STARTUPINFO
LPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_INFORMATION
);


위의 코드중에 Loader만들기에 필요한 부분만 설명하도록 하겠습니다.

lpApplicationName : 타켓프로그램의 경로 및 파일명(예: c:\dir\changeme.exe)
lpCommandLine : 타켓이 실행할 때 주어지는 파라메터를 설정하기 위해 사용(로더만들 때는 NULL로 설정)
dwCreationFlags : 로더로 타켓을 메모리에 로드시켰을 때, 해당 프로세스를 정지시켜주기 위한 설정에 사용(CREATE_SUSPENDED 상수 사용)
lpStartupInfo : CreateWindow함수나 ShowWindow함수와 같이 main window의 속성을 명시하기 위해 CreateProcess과 같이 사용되는 구조체
lpProcessInformation : 타켓이 메모리에 로드되었을 때, 프로세스정보가 채워지는 구조체(process handle, thread handle, process/thread ID를 가지고 있음)



1-2. 타켓이 메모리에 로드 된 후 해당 프로세스를 중지시켜야 합니다.

이를 위한 API는 다음과 같습니다.
DWORD ResumeThread(
HANDLE hThread // identifies thread to restart
);
ResumeThread는 정지된 Thread를 다시 실행시키는 일을 합니다.

DWORD SuspendThread(
HANDLE hThread // handle to the thread
);

SuspendThread는 실행중인 Thread를 정지시키는 일을 합니다.
위에서 사용되는 hTread handle정보는 LPPROCESS_INFORMATION 구조체가 가지고 있습니다.


1-3. 이제 우리가 원하는 작업인 패치를 할 수 있게 됩니다.



패치를 하기 위해서는 메모리를 읽고 쓰는 API를 사용합니다.

Wirte API :

BOOL WriteProcessMemory(
HANDLE hProcess, // handle to process whose memory is written to
LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // pointer to buffer to write data to
DWORD nSize, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);

Read API :

BOOL ReadProcessMemory(
HANDLE hProcess, // handle to the process whose memory is read
LPCVOID lpBaseAddress, // address to start reading
LPVOID lpBuffer, // address of buffer to place read data
DWORD nSize, // number of bytes to read
LPDWORD lpNumberOfBytesRead // address of number of bytes read
);

위의 동작에 사용되는 API는 다음 절 예제를 보시면서 이해하시길 바랍니다



2. Loader 예제

예제에 사용되는 타켓 파일은 zip을 풀면 나오는 changeme.exe입니다.



이 예제에서 Loader를 만드는 목적은 changeme.exe 실행 시 나오는 OK버튼을 밑에 있는 문자인
“change me!”를 우리가 원하는 문자로 패치하는 것입니다. 이를 위해서는 changeme.exe에 있는 “change me!”문자열 주소를 찾아야 합니다.


Ollydbg로 changeme.exe를 로드시킨 후, 문자열을 검색합니다.


“change me!”문자열이 0x00403020에 들어가 있군요…

이제 1절 내용을 토대로 0x00403020에 있는 “change me!”를 “good”로 바꾸는 Loader 코드를 보도록 하죠…..

#include <stdio.h>
#include <windows.h>

char Filename[] = ".\\Changeme.exe"; //Loader가 있는 동일폴더에 타켓으로 “Changeme.exe”지정
char notloaded[] = "changeme.exe가 실행이 안되었군~";
char Letsgo[] = "프로세스가 실행되었습니다. 이제 패치를 해야죠~";
char OldText[20]; //기존 문자 저장 “change me!”
char NewText[] = "Written by good "; //기존 문자를 “good”로 바꾸기 위한 문자열

STARTUPINFO startupinfo;
PROCESS_INFORMATION processinfo;

unsigned long bytewritten;
int uExitCode;



void main(){
//processinfo, startupinfo 초기화
memset(&processinfo, 0, sizeof(PROCESS_INFORMATION));
memset(&startupinfo, 0, sizeof(STARTUPINFO));
startupinfo.cb = sizeof(STARTUPINFO);
//프로세스를 생성시키고, Changeme 로드 후 정지(CREATE_SUSPENDED)

BOOL bRes = CreateProcess(Filename, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupinfo, &processinfo);


if(bRes == NULL) //프로세스가 생성되었는지 점검
MessageBox(NULL, notloaded, NULL, MB_ICONEXCLAMATION);
else {
MessageBox(NULL, Letsgo, NULL, MB_OK);
//0x00403020에 있는 “changeme!”를 잃어들여서 OldText에 저장
ReadProcessMemory(processinfo.hProcess, (LPVOID)0x00403020, OldText, 26, NULL);
//”good”를 0x00403020에 저장
WriteProcessMemory(processinfo.hProcess, (LPVOID)0x00403020, NewText, 20, &bytewritten);
//정지된 프로세스를 다시 실행
ResumeThread(processinfo.hThread);

printf("Original string : %s\n",OldText);
printf("New String : %s\n",NewText);

}

ExitProcess(1);

}


위의 코드로 만들어진 Loader.exe를 changeme.exe 실행 후 실행 해보시면.. 패치가 됨을 알 수 있습니다.
Posted by Mocker