DLL 인젝션 간단한 예제
DLL Injection에 대한 튜토리얼을 진행해 봤으니, 예제를 함 해보아야 겠다는 생각이 들어서 예제를 시작한다.
MinGW에서 모든 것을 진행 했으므로 에셈블리 부분은 따로 생각을 해보아야 할 문제 일듯... 이건 단지 나의 생각이긴 한데, GCC가 만들어내는 것과 MS 컴파일러가 이해하는 어셈블리는 약간 다르다는 판단이 섰고, 예제를 만들면서 컴파일을 해 본 결과 컴파일 만드로 해결되지 않았음..능력에 문제인가 한다....아...
시나리오
시나리오는 간단하게 다음과 같이 된다.
노드패드를 실행하고 나서, 해당 실행파일을 실행하면 안녕이라는 메시지가 뜬다.
작성형태
우선 injector 실행파이을 만들고, 이 실행 파일은 dll을 로딩하는 역할 을 하는 것으로 한다.
그리고 test.dll 파일을 하나 만들어서 notepad.exe가 실행이 되면 인사말을 찍는 정도록 마쳐야 겠다.
결과물
결과는 시나리오에서 처럼 다음과 같은 순으로 진행한다.
1. 노트패드를 실행한다.
![](https://blog.kakaocdn.net/dn/mqA3Q/btrVStmyh9U/MxYzwMDq2ZoyqiwS7KSouK/img.png)
사진 설명을 입력하세요.
2. 실행파일을 실행한다.
이때 안녕이라는 메시지가 나오도록...
![](https://blog.kakaocdn.net/dn/mRYjv/btrVUzMHfRx/S8AQ4mBcBGdZ40OmJoNLuK/img.png)
정말 이게 다 인가??
여하튼 문제점은 계속 업데이트 되어야 할 것인데 몇가지를 집어 본다.
1. 기본적으로 위의 시나리오 대로만 해야한다는 것
- 노트패드를 띄우는 동시에 이놈은 이 이벤트를 감지하고 인사 메시지를 뿌려야 하는 것이 아닌가?
2. 노트패트는 한번 뿐..
소스 코드상에서도 그렇게 되어 있긴 하지만, "notepad.exe"를 찾아서 실행하도록 되어 있다.
코드를 보면
DWORD pID = GetTargetThreadIDFromProcName("notepad.exe");
그리고 위에서 받은 pID를 사용해서 인젝션한다.
if(!Inject(pID, buf))
근데, 문제는 한번 notepad.exe를 실행하고 나면 다시 모든 노트패드(몇개가 되었든..) 다 죽이고 나서 다시 하나 띄워야만 된다는 것이다.
결론...
곰곰히 생각 해 보니 뭐가 잘못되었는 지는 잘 모르겠다.. 애덜 장난같기도 하고...
아직까지는 잘 모르는 걸로...
부록 1. injector.c
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <conio.h>
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
BOOL Inject(DWORD pID, const char * DLL_NAME);
DWORD GetTargetThreadIDFromProcName(const char * ProcName);
int main(int argc, char * argv[])
{
// Retrieve process ID
DWORD pID = GetTargetThreadIDFromProcName("notepad.exe");
// Get the dll's full path name
char buf[MAX_PATH] = {0};
GetFullPathName("test.dll", MAX_PATH, buf, NULL);
printf(buf);
printf("\n");
// Inject our main dll
if(!Inject(pID, buf))
{
printf("DLL Not Loaded!");
}else{
printf("DLL Loaded!");
}
_getch();
return FALSE;
}
BOOL Inject(DWORD pID, const char * DLL_NAME)
{
HANDLE Proc;
HMODULE hLib;
char buf[50] = {0};
LPVOID RemoteString, LoadLibAddy;
if(!pID)
{
sprintf(buf, "Invalid process id: %d\r\n", GetLastError());
MessageBox(NULL, buf, "Loader", MB_OK);
printf(buf);
return FALSE;
}
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", MB_OK);
printf(buf);
return FALSE;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(NULL != LoadLibAddy)
{
// Allocate space in the process for our DLL
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our DLL
CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibAddy, RemoteString, 0, NULL);
}
else
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", MB_OK);
printf(buf);
return FALSE;
}
CloseHandle(Proc);
return TRUE;
}
DWORD GetTargetThreadIDFromProcName(const char * ProcName)
{
PROCESSENTRY32 pe;
HANDLE thSnapShot;
BOOL retval, ProcFound = FALSE;
thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapShot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: Unable to create toolhelp snapshot!", "2MLoader", MB_OK);
printf("Error: Unable to create toolhelp snapshot!");
return FALSE;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapShot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, ProcName))
{
return pe.th32ProcessID;
}
retval = Process32Next(thSnapShot, &pe);
}
return FALSE;
}
부록 2. testdll.c
#include "main.h"
DWORD DLL_EXPORT WINAPI ShowMessageBox(LPVOID lpParam)
{
INITCOMMONCONTROLSEX iccex = {
sizeof(INITCOMMONCONTROLSEX), ICC_STANDARD_CLASSES
};
InitCommonControlsEx(&iccex);
IsGUIThread(TRUE);
OutputDebugString(TEXT("test.dll: Displaying MessageBox"));
if(MessageBox(HWND_DESKTOP, TEXT("안녕"), TEXT("안녕 이게 다야"), MB_OK | MB_ICONINFORMATION) == 0){
TCHAR szBuffer[64];
wsprintf(szBuffer, TEXT("MessageBox Error: %u"), GetLastError());
OutputDebugString(szBuffer);
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
{
DWORD dwThreadId;
DisableThreadLibraryCalls(hInst);
OutputDebugString(TEXT("test.dll: DLL_PROCESS_ATTACH"));
CreateThread(NULL, 0, ShowMessageBox, NULL, 0, &dwThreadId);
}
break;
case DLL_PROCESS_DETACH:
OutputDebugString(TEXT("test.dll: DLL_PROCESS_DETACH"));
break;
}
return TRUE;
}
부록 3. main.h
#ifndef __MAIN_H__
#define __MAIN_H__
//
// compiled with:
// cl test.c /link /dll /out:test.dll user32.lib kernel32.lib comctl32.lib
//
#ifndef _WIN32_IE
/* define _WIN32_IE if you really want it */
#if 1
#define _WIN32_IE 0x0400 //for INITCOMMONCONTROLSEX
#endif
#endif
#ifndef _WIN32_WINNT
/* define _WIN32_WINNT if you really want it */
#if 1
#define _WIN32_WINNT 0x501 //for ICC_STANDARD_CLASSES
#endif
#endif
#include <windows.h>
#include <commctrl.h>
/* To use this exported function of dll, include this header
* in your project.
*/
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
/* Not needed for now
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT SomeFunction(const LPCSTR sometext);
#ifdef __cplusplus
}
#endif
*/
#endif // __MAIN_H__
부록 4. 컴파일
gcc -c -I/hack/incl -DBUILD_DLL testdll.c -o testdll.o testdll.c
gcc -Wl,--kill-at -shared -o /hack/dll/test.dll testdll.o -lcomctl32
gcc -c -I/hack/incl injector2.c -o injector2.o
gcc -Wl,--kill-at -o /hack/exec/injector.exe injector2.o
이상.
'프로그래밍' 카테고리의 다른 글
C# - Thread (0) | 2023.02.24 |
---|---|
Mosquitto와 Paho 클라이언트라이브러리를 사용 (0) | 2023.02.22 |
열거 유형 - 정량적 연구 (0) | 2023.02.20 |
SQL 문장 들여쓰기 (0) | 2023.02.17 |
[JavaScript] console.log() 함수에 여러변수를 한줄로 ? (0) | 2023.02.15 |