1
+ <?php
2
+ require_once "c_mem.php " ;
3
+ class c_pe_mapper
4
+ {
5
+ private $ bin ;
6
+ private $ mem_mgr ;
7
+ private $ size_of_image , $ base ;
8
+ private $ sections = array ( );
9
+ private $ imports = array ( );
10
+ private $ relocs = array ( );
11
+ private $ mapped_bin = array ( );
12
+ private $ entry = 0 ;
13
+
14
+ public function __construct ( string $ path ) {
15
+ $ handle = fopen ( $ path , "rb " );
16
+ $ file_size = filesize ( $ path );
17
+ $ contents = fread ( $ handle , $ file_size );
18
+ $ this ->bin = unpack ( "C* " , $ contents );
19
+ fclose ( $ handle );
20
+
21
+ $ this ->mem_mgr = new c_mem ( );
22
+ }
23
+
24
+ public function initialize ( ) : int {
25
+ $ dos_nt_offset = $ this ->mem_mgr ->read_dword ( $ this ->bin , 0x3C + 0x1 );
26
+ $ nt_sig = $ this ->mem_mgr ->read_dword ( $ this ->bin , $ dos_nt_offset + 0x1 );
27
+
28
+ if ( $ nt_sig != 0x4550 )
29
+ return 1 ; // invalid nt signature
30
+
31
+ $ size_of_image = $ this ->mem_mgr ->read_dword ( $ this ->bin , $ dos_nt_offset + 0x50 + 0x1 );
32
+ $ size_of_header = $ this ->mem_mgr ->read_word ( $ this ->bin , $ dos_nt_offset + 0x54 + 0x1 );
33
+
34
+ $ this ->base = $ this ->mem_mgr ->read_dword ( $ this ->bin , $ dos_nt_offset + 0x34 + 0x1 );
35
+ $ this ->size_of_image = $ size_of_image ;
36
+
37
+ $ mapped_bin = array_fill ( 0 , $ size_of_image , 0 );
38
+ $ mapped_bin = $ this ->mem_mgr ->mem_copy ( $ this ->bin , $ mapped_bin , 0 , 1 , $ size_of_header );
39
+
40
+ $ num_of_sections = $ this ->mem_mgr ->read_word ( $ mapped_bin , $ dos_nt_offset + 0x6 );
41
+ $ section_header = array_fill ( 0 , 0x28 * $ num_of_sections , 0 );
42
+ $ section_header = $ this ->mem_mgr ->mem_copy ( $ mapped_bin , $ section_header , 0 ,
43
+ $ dos_nt_offset + 0xF8 , 0x28 * $ num_of_sections );
44
+
45
+ $ this ->entry = $ this ->mem_mgr ->read_dword ( $ mapped_bin , $ dos_nt_offset + 0x28 );
46
+
47
+ for ( $ i = 0 ; $ i < $ num_of_sections ; $ i ++ ) {
48
+ $ name = "" ;
49
+ foreach ( $ this ->mem_mgr ->read_qword ( $ section_header , $ i * 0x28 ) as $ char )
50
+ $ name .= chr ( $ char );
51
+
52
+ $ va = $ this ->mem_mgr ->read_dword ( $ section_header , $ i * 0x28 + 0xC );
53
+ $ ptr = $ this ->mem_mgr ->read_dword ( $ section_header , $ i * 0x28 + 0x14 );
54
+ $ size = $ this ->mem_mgr ->read_dword ( $ section_header , $ i * 0x28 + 0x10 );
55
+
56
+ $ this ->sections [ $ name ] = array (
57
+ "virtual_address " => $ va ,
58
+ "ptr_to_raw " => $ ptr ,
59
+ "size " => $ size
60
+ );
61
+
62
+ if ( $ name == ".reloc " ) {
63
+ for ( $ j = 0 ; $ j < $ size ; $ j ++ )
64
+ $ this ->bin [ $ ptr + $ j + 1 ] = 0 ;
65
+ }
66
+
67
+ $ mapped_bin = $ this ->mem_mgr ->mem_copy ( $ this ->bin , $ mapped_bin , $ va , $ ptr + 1 , $ size );
68
+ }
69
+
70
+ $ directories = array_fill ( 0 , 0x8 * 16 , 0 );
71
+ $ directories = $ this ->mem_mgr ->mem_copy ( $ mapped_bin , $ directories , 0 ,
72
+ $ dos_nt_offset + 0x78 , 0x8 * 16 );
73
+
74
+ $ imp_dir_offset = $ this ->mem_mgr ->read_dword ( $ directories , 0x8 );
75
+
76
+ $ imports = array_fill ( 0 , $ this ->mem_mgr ->read_dword ( $ directories , 0x8 + 4 ), 0 );
77
+ $ imports = $ this ->mem_mgr ->read_mem ( $ mapped_bin , $ imp_dir_offset , count ( $ imports ) );
78
+
79
+ while ( $ this ->mem_mgr ->read_dword ( $ imports , 0 ) > 0 ) {
80
+ $ module_name = $ this ->mem_mgr ->read_string ( $ mapped_bin ,
81
+ $ this ->mem_mgr ->read_dword ( $ imports , 0xC ) );
82
+
83
+ $ thunk_offset = 0 ;
84
+ $ orig_thunk = $ this ->mem_mgr ->read_mem ( $ mapped_bin ,
85
+ $ this ->mem_mgr ->read_dword ( $ imports , 0x0 ), 4 );
86
+
87
+ if ( mb_substr ( $ module_name , 0 , 7 ) == "api-ms- " )
88
+ $ module_name = "ucrtbase.dll " ;
89
+
90
+ while ( $ this ->mem_mgr ->read_dword ( $ orig_thunk , 0 ) > 0 ) {
91
+ $ thunk_data = $ this ->mem_mgr ->read_dword ( $ orig_thunk , 0 );
92
+ if ( $ thunk_data & 0x80000000 ) {
93
+ $ function = $ thunk_data & 0xFFFF ;
94
+ } else {
95
+ $ function = $ this ->mem_mgr ->read_string ( $ mapped_bin ,
96
+ $ this ->mem_mgr ->read_dword ( $ orig_thunk , 0 ) + 2 );
97
+ }
98
+
99
+ $ this ->imports [ $ module_name ][ $ function ] = $ this ->mem_mgr ->read_dword ( $ imports , 0x10 )
100
+ + $ thunk_offset ;
101
+
102
+ $ thunk_offset += 4 ;
103
+ $ orig_thunk = $ this ->mem_mgr ->read_mem ( $ mapped_bin ,
104
+ $ this ->mem_mgr ->read_dword ( $ imports , 0x0 ) + $ thunk_offset , 4 );
105
+ }
106
+
107
+ $ imp_dir_offset += 0x14 ;
108
+ $ imports = $ this ->mem_mgr ->read_mem ( $ mapped_bin , $ imp_dir_offset , count ( $ imports ) );
109
+ }
110
+
111
+ $ reloc_dir_offset = $ this ->mem_mgr ->read_dword ( $ directories , 0x8 * 5 );
112
+
113
+ $ relocs = array_fill ( 0 , $ this ->mem_mgr ->read_dword ( $ directories , 0x8 * 5 + 4 ), 0 );
114
+ $ relocs = $ this ->mem_mgr ->read_mem ( $ mapped_bin , $ reloc_dir_offset , count ( $ relocs ) );
115
+
116
+ while ( $ this ->mem_mgr ->read_dword ( $ relocs , 0 ) > 0 ) {
117
+ // CODE VIRTUALIZER AND THEMIDA SUPPORT! NEVER SEEN BEFORE
118
+ if ( $ this ->mem_mgr ->read_dword ( $ relocs , 0 ) >= $ size_of_image )
119
+ break ;
120
+ // END OF CODE VIRTUALIZER AND THEMIDA SUPPORT! NEVER SEEN BEFORE
121
+
122
+ $ num_of_relocs = ( $ this ->mem_mgr ->read_dword ( $ relocs , 4 ) - 8 ) / 2 ;
123
+ $ block = $ this ->mem_mgr ->read_mem ( $ mapped_bin , $ reloc_dir_offset + 8 , $ num_of_relocs * 2 );
124
+
125
+ for ( $ i = 0 ; $ i < $ num_of_relocs ; $ i ++ ) {
126
+ $ block_offset = $ this ->mem_mgr ->read_word ( $ block , $ i * 2 );
127
+ if ( $ block_offset >> 0xC != 3 )
128
+ continue ;
129
+
130
+ $ this ->relocs [ ] = $ this ->mem_mgr ->read_dword ( $ relocs , 0 ) + ( $ block_offset & 0xFFF );
131
+ }
132
+
133
+ $ reloc_dir_offset += $ this ->mem_mgr ->read_dword ( $ relocs , 4 );
134
+ $ relocs = $ this ->mem_mgr ->read_mem ( $ mapped_bin , $ reloc_dir_offset , count ( $ relocs ) );
135
+ }
136
+
137
+ $ this ->mapped_bin = $ mapped_bin ;
138
+ return 0 ;
139
+ }
140
+
141
+ public function map ( int $ base , array $ imports ) : array {
142
+ $ mapped_bin = array_fill ( 0 , $ this ->size_of_image , 0 );
143
+ foreach ( $ this ->sections as $ section ) {
144
+ $ mapped_bin = $ this ->mem_mgr ->mem_copy ( $ this ->mapped_bin , $ mapped_bin ,
145
+ $ section [ "virtual_address " ], $ section [ "virtual_address " ], $ section [ "size " ] );
146
+ }
147
+
148
+ foreach ( $ this ->relocs as $ reloc ) {
149
+ $ mapped_bin = $ this ->mem_mgr ->set_dword ( $ mapped_bin , $ reloc ,
150
+ $ this ->mem_mgr ->read_dword ( $ mapped_bin , $ reloc ) + $ base - $ this ->base );
151
+ }
152
+
153
+ foreach ( $ this ->imports as $ module => $ functions ) {
154
+ if ( empty ( $ imports [ $ module ] ) || !is_array ( $ imports [ $ module ] ) )
155
+ return array ( );
156
+
157
+ foreach ( $ functions as $ function => $ rva ) {
158
+ if ( empty ( $ imports [ $ module ][ $ function ] ) )
159
+ return array ( );
160
+
161
+ $ mapped_bin = $ this ->mem_mgr ->set_dword ( $ mapped_bin , $ rva , $ imports [ $ module ][ $ function ] );
162
+ }
163
+ }
164
+
165
+ return $ mapped_bin ;
166
+ }
167
+
168
+ public function get_loader_data ( ) : array {
169
+ $ imports = array ( );
170
+ foreach ( $ this ->imports as $ module => $ functions ) {
171
+ foreach ( $ functions as $ function => $ rva )
172
+ $ imports [ $ module ][ ] = $ function ;
173
+ }
174
+
175
+ return (
176
+ array (
177
+ "imports " => $ imports ,
178
+ "size " => $ this ->size_of_image ,
179
+ "entry " => $ this ->entry
180
+ )
181
+ );
182
+ }
183
+ }
0 commit comments