1
+ /* *
2
+ A demo of a basic manual PE loader - you can use it as a starting point for your own project,
3
+ or delete it and start from scratch
4
+ */
5
+
1
6
#include < Windows.h>
2
7
#include < iostream>
3
8
#include < tchar.h>
4
9
5
10
#include < peconv.h> // include libPeConv header
6
11
7
- /* *
8
- A demo of a basic manual PE loader - you can use it as a starting point for your own project,
9
- or delete it and start from the scratch
10
- */
11
- int load_and_run (LPCTSTR pe_path)
12
+ BYTE* g_Payload = nullptr ;
13
+ size_t g_PayloadSize = 0 ;
14
+
15
+ // manually load the PE file using libPeConv
16
+ bool load_payload (LPCTSTR pe_path)
12
17
{
13
18
// manually load the PE file using libPeConv:
14
- size_t v_size = 0 ;
19
+ size_t g_PayloadSize = 0 ;
15
20
#ifdef LOAD_FROM_PATH
16
21
// if the PE is dropped on the disk, you can load it from the file:
17
- BYTE* my_pe = peconv::load_pe_executable (pe_path, v_size);
18
- #else
22
+ g_Payload = peconv::load_pe_executable (pe_path, g_PayloadSize);
23
+ #else // load from memory buffer
24
+ /*
25
+ in this example the memory buffer is first loaded from the disk,
26
+ but it can as well be fetch from resources, or a hardcoded buffer
27
+ */
19
28
size_t bufsize = 0 ;
20
- BYTE *buffer = peconv::load_file (pe_path, bufsize);
29
+ BYTE* buf = peconv::load_file (pe_path, bufsize);
30
+ if (buf) {
31
+ // if the file is NOT dropped on the disk, you can load it directly from a memory buffer:
32
+ g_Payload = peconv::load_pe_executable (buf, bufsize, g_PayloadSize);
21
33
22
- // if the file is NOT dropped on the disk, you can load it directly from a memory buffer:
23
- BYTE* my_pe = peconv::load_pe_executable (buffer, bufsize, v_size);
34
+ // at this point we can free the buffer with the raw payload:
35
+ peconv::free_file (buf); buf = nullptr ;
36
+
37
+ if (!g_Payload) {
38
+ return false ;
39
+ }
40
+ }
24
41
#endif
25
- if (!my_pe) {
42
+ return true ;
43
+ }
44
+
45
+ int run_payload ()
46
+ {
47
+ if (!g_Payload) {
48
+ std::cerr << " [!] The payload is not loaded!\n " ;
26
49
return -1 ;
27
50
}
28
-
29
51
// if the loaded PE needs to access resources, you may need to connect it to the PEB:
30
- peconv::set_main_module_in_peb ((HMODULE)my_pe );
52
+ peconv::set_main_module_in_peb ((HMODULE)g_Payload );
31
53
32
54
// if needed, you can run TLS callbacks before the Entry Point:
33
- peconv::run_tls_callbacks (my_pe, v_size );
55
+ peconv::run_tls_callbacks (g_Payload, g_PayloadSize );
34
56
35
57
// calculate the Entry Point of the manually loaded module
36
- DWORD ep_rva = peconv::get_entry_point_rva (my_pe );
58
+ DWORD ep_rva = peconv::get_entry_point_rva (g_Payload );
37
59
if (!ep_rva) {
60
+ std::cerr << " [!] Cannot fetch EP!\n " ;
38
61
return -2 ;
39
62
}
40
- ULONG_PTR ep_va = ep_rva + (ULONG_PTR)my_pe;
41
- // assuming that the payload is an EXE file (not DLL) this will be the simplest prototype of the main:
42
- int (*new_main)() = (int (*)())ep_va;
63
+ const ULONG_PTR ep_va = ep_rva + (ULONG_PTR)g_Payload;
64
+
65
+ // run appropriate version of payload's main:
66
+ int ret = 0 ;
67
+ if (peconv::is_module_dll (g_Payload)) {
68
+ // the prototype of the DllMain fuction:
69
+ BOOL WINAPI _DllMain (
70
+ HINSTANCE hinstDLL, // handle to DLL module
71
+ DWORD fdwReason, // reason for calling function
72
+ LPVOID lpvReserved); // reserved
73
+ auto new_main = reinterpret_cast <decltype (&_DllMain)>(ep_va);
74
+
75
+ // call the Entry Point of the manually loaded PE :
76
+ ret = new_main ((HINSTANCE)g_Payload, DLL_PROCESS_ATTACH, 0 );
77
+ }
78
+ else {
79
+ // the simplest prototype of the main fuction:
80
+ int basic_main (void );
81
+ auto new_main = reinterpret_cast <decltype (&basic_main)>(ep_va);
43
82
44
- // call the Entry Point of the manually loaded PE:
45
- return new_main ();
83
+ // call the Entry Point of the manually loaded PE:
84
+ ret = new_main ();
85
+ }
86
+ return ret;
46
87
}
47
88
48
89
int _tmain (int argc, LPTSTR argv[])
@@ -52,5 +93,9 @@ int _tmain(int argc, LPTSTR argv[])
52
93
return 0 ;
53
94
}
54
95
const LPTSTR pe_path = argv[1 ];
55
- return load_and_run (pe_path);
96
+ if (!load_payload (pe_path)) {
97
+ return -1 ;
98
+ }
99
+ std::cout << " Payload loaded!\n " ;
100
+ return run_payload ();
56
101
}
0 commit comments