1+ #include <windows.h>
2+ #include <stdio.h>
3+ #include <stdint.h>
4+ #include <stdlib.h>
5+
6+ DWORD RVAtoFileOffset (DWORD RVA , PIMAGE_NT_HEADERS pNtHeader , PIMAGE_SECTION_HEADER pSec );
7+ DWORD GetProcOffset (const char * funcName , LPVOID pBuf );
8+
9+ // 辅助函数:将32位整数打包为小端字节序
10+ void pack (uint32_t val , uint8_t * bytes ) {
11+ bytes [0 ] = val & 0xFF ;
12+ bytes [1 ] = (val >> 8 ) & 0xFF ;
13+ bytes [2 ] = (val >> 16 ) & 0xFF ;
14+ bytes [3 ] = (val >> 24 ) & 0xFF ;
15+ }
16+
17+ int wmain (int argc , wchar_t * argv []) {
18+
19+ printf ("╔══════════════════════════════════════════════════════════════════════════════════════╗\n" );
20+ printf ("║ Convert2Shellcode_embed ║\n" );
21+ printf ("║------------------------------------------------------------------------------------- ║\n" );
22+ printf ("║ Function: An improved version of RDI requires implementing the ReflectLoader function║\n" );
23+ printf ("║ in the DLL by yourself and also needs to be exported. ║\n" );
24+ printf ("║ Author:oneday ║\n" );
25+ printf ("║ Compilation Date:%hs %hs ║\n" , __DATE__ , __TIME__ );
26+ printf ("╚══════════════════════════════════════════════════════════════════════════════════════╝\n" );
27+ printf ("\n" );
28+
29+ // 检查参数数量
30+ if (argc < 2 ) {
31+ printf ("[-] Error: Missing DLL path parameter\n" );
32+ printf ("[*] Usage: Convert2Shellcode_embed.exe <DLL Path> [Output File Path] [The Export Function Name of Loader]\n" );
33+ printf ("[*] Example 1: Convert2Shellcode_embed.exe C:\\path\\to\\ReflectiveDLL.dll\n" );
34+ printf ("[*] Example 2: Convert2Shellcode_embed.exe C:\\path\\to\\ReflectiveDLL.dll C:\\path\\to\\Shellcode.bin\n" );
35+ printf ("[*] Example 3: Convert2Shellcode_embed.exe C:\\path\\to\\ReflectiveDLL.dll C:\\path\\to\\Shellcode.bin ReflectiveLoader\n" );
36+ return 1 ;
37+ }
38+
39+ uint8_t bootstrap [24 ];
40+ uint8_t * dllBytes = NULL ;
41+ size_t dllSize = 0 ;
42+
43+ const wchar_t * dllPath = argv [1 ];
44+ FILE * dllFile = _wfopen (dllPath , L"rb" );
45+ if (!dllFile ) {
46+ printf ("[-] Error: Unable to open file %s (Error code: %d)\n" , dllPath , GetLastError ());
47+ return 1 ;
48+ }
49+ printf ("[+] Successfully opened %s\n" , dllPath );
50+
51+ // 获取文件大小
52+ fseek (dllFile , 0 , SEEK_END );
53+ dllSize = ftell (dllFile );
54+ fseek (dllFile , 0 , SEEK_SET );
55+ if (dllSize == 0 ) {
56+ printf ("[-] Error: File size is 0 - %s\n" , dllPath );
57+ fclose (dllFile );
58+ return 1 ;
59+ }
60+ printf ("[*] File size is %zu\n" , dllSize );
61+
62+ // 读取文件内容
63+ dllBytes = (uint8_t * )malloc (dllSize );
64+ if (!dllBytes ) {
65+ printf ("[-] Error: Memory allocation failed (requested dllSize: %zu bytes)\n" , dllSize );
66+ fclose (dllFile );
67+ return 1 ;
68+ }
69+ printf ("[+] Memory allocation successful, address is 0x%x\n" , dllBytes );
70+
71+ size_t bytesRead = fread (dllBytes , 1 , dllSize , dllFile );
72+ fclose (dllFile );
73+ if (bytesRead != dllSize ) {
74+ printf ("[-] Error: File read incomplete (read %zu/%zu bytes)\n" , bytesRead , dllSize );
75+ free (dllBytes );
76+ return 1 ;
77+ }
78+ printf ("[*] %zu bytes read into memory\n" , bytesRead );
79+
80+ // 假设 ReflectLoader 是目标函数名
81+ const wchar_t * Wide_ReflectiveLoaderName = (argc >= 4 ) ? argv [3 ] : L"ReflectiveLoader" ;
82+
83+
84+ // 计算所需缓冲区大小
85+ size_t size = wcstombs (NULL , Wide_ReflectiveLoaderName , 0 ) + 1 ;
86+ char * ReflectiveLoaderName = (char * )malloc (size );
87+
88+ // 执行转换
89+ wcstombs (ReflectiveLoaderName , Wide_ReflectiveLoaderName , size );
90+
91+ DWORD RDIOffset = 0 ;
92+ RDIOffset = GetProcOffset (ReflectiveLoaderName , dllBytes );
93+
94+ if (!RDIOffset ) {
95+ printf ("[-] Error: fail to get RDIOffset)\n" );
96+ free (dllBytes );
97+ free (ReflectiveLoaderName );
98+ return 1 ;
99+ }
100+
101+ free (ReflectiveLoaderName );
102+
103+ // 构建stub
104+ int index = 0 ;
105+ uint8_t stub [23 ];
106+
107+ // pop r10
108+ stub [index ++ ] = 0x4D ;
109+ stub [index ++ ] = 0x5A ;
110+
111+ // push r10
112+ stub [index ++ ] = 0x41 ;
113+ stub [index ++ ] = 0x52 ;
114+
115+ // call 0
116+ stub [index ++ ] = 0xE8 ;
117+ stub [index ++ ] = 0x00 ;
118+ stub [index ++ ] = 0x00 ;
119+ stub [index ++ ] = 0x00 ;
120+ stub [index ++ ] = 0x00 ;
121+
122+ // pop rbx
123+ stub [index ++ ] = 0x5B ;
124+
125+ // add rbx,<RDIOffset-9>
126+ stub [index ++ ] = 0x48 ;
127+ stub [index ++ ] = 0x81 ;
128+ stub [index ++ ] = 0xC3 ;
129+ pack (RDIOffset - 9 , stub + index );
130+ index += 4 ;
131+
132+ // push rbp
133+ stub [index ++ ] = 0x55 ;
134+
135+ // mov rbp, rsp
136+ stub [index ++ ] = 0x48 ;
137+ stub [index ++ ] = 0x89 ;
138+ stub [index ++ ] = 0xE5 ;
139+
140+ // call rbx
141+ stub [index ++ ] = 0xFF ;
142+ stub [index ++ ] = 0xD3 ;
143+
144+ uint8_t * finalcode = (uint8_t * )malloc (dllSize );
145+ if (!finalcode ) {
146+ printf ("[-] Error: Memory allocation failed (requested finalSize: %zu bytes)\n" , dllSize );
147+ free (dllBytes );
148+ return 1 ;
149+ }
150+ printf ("[+] Memory allocation successful, address is 0x%x\n" , finalcode );
151+
152+ // 构造最终的shellcode
153+ memcpy (finalcode , dllBytes , dllSize );
154+ memcpy (finalcode , stub , index );
155+
156+ // 释放 DLL 缓冲区
157+ free (dllBytes );
158+ dllBytes = NULL ;
159+
160+ // 处理输出文件参数
161+ const wchar_t * outputPath = (argc >= 3 ) ? argv [2 ] : L"shellcode_embed.bin" ;
162+
163+ // 写入文件
164+ HANDLE hFile = CreateFileW (
165+ outputPath ,
166+ GENERIC_WRITE ,
167+ 0 ,
168+ NULL ,
169+ CREATE_ALWAYS ,
170+ FILE_ATTRIBUTE_NORMAL ,
171+ NULL
172+ );
173+
174+ if (hFile == INVALID_HANDLE_VALUE ) {
175+ printf ("[-] Error: Unable to create output file %s (Error code: %d)\n" , outputPath , GetLastError ());
176+ free (finalcode );
177+ return 1 ;
178+ }
179+
180+ DWORD bytesWritten ;
181+ BOOL writeResult = WriteFile (
182+ hFile ,
183+ finalcode ,
184+ (DWORD )dllSize ,
185+ & bytesWritten ,
186+ NULL
187+ );
188+
189+ if (!writeResult || bytesWritten != dllSize ) {
190+ printf ("[-] Error: Failed to write to file (wrote %lu/%zu bytes, error code: %d)\n" ,
191+ bytesWritten , dllSize , GetLastError ());
192+ CloseHandle (hFile );
193+ free (finalcode );
194+ return 1 ;
195+ }
196+
197+ FlushFileBuffers (hFile );
198+ CloseHandle (hFile );
199+ printf ("[+] Successfully generated shellcode file: %s (Size: %zu bytes)\n" , outputPath , dllSize );
200+
201+ return 0 ;
202+ }
203+
204+ //作用:RVA->文件偏移地址
205+ //公式:文件偏移 = 节区文件起始地址(PointerToRawData) + (RVA - 节区虚拟起始地址(VirtualAddress))
206+ DWORD RVAtoFileOffset (DWORD RVA , PIMAGE_NT_HEADERS pNtHeader , PIMAGE_SECTION_HEADER pSec ) {
207+
208+ // 遍历节区表
209+ DWORD SectionNumber = pNtHeader -> FileHeader .NumberOfSections ;
210+ for (int i = 0 ; i < SectionNumber ; i ++ ) {
211+ // 检查RVA是否在当前节区的范围内
212+ if (RVA >= pSec [i ].VirtualAddress && RVA < pSec [i ].VirtualAddress + pSec [i ].SizeOfRawData ) {
213+ // 转换RVA到文件偏移地址
214+ return pSec [i ].PointerToRawData + (RVA - pSec [i ].VirtualAddress );
215+ }
216+ }
217+ // 如果未找到对应的节区,返回无效值
218+ return 0xFFFFFFFF ;
219+ }
220+
221+ //作用:该函数通过导出表获得指定函数的地址
222+ DWORD GetProcOffset (const char * funcName , LPVOID pBuf ) {
223+
224+ //定位一些相关文件头
225+ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER )pBuf ;
226+ PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS )((BYTE * )pBuf + pDosHeader -> e_lfanew );
227+ PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER )((LPBYTE )pNtHeader + sizeof (IMAGE_NT_HEADERS ));
228+
229+ //获取导出表地址及大小,注意这里是RVA
230+ DWORD exportDirRVA = pNtHeader -> OptionalHeader .DataDirectory [0 ].VirtualAddress ;
231+ DWORD exportDirSize = pNtHeader -> OptionalHeader .DataDirectory [0 ].Size ;
232+
233+ if (!exportDirRVA ) {
234+ printf ("[-] Error: This DLL does not have an export table.\n" );
235+ return NULL ;
236+ }
237+ //定位导出表
238+ //得到的偏移地址是RVA,但是咱们的文件现在只是磁盘文件,所以需要转换为文件偏移
239+ DWORD exportDirFileOffset = RVAtoFileOffset ((DWORD )exportDirRVA , pNtHeader , pSec );
240+
241+ //转换之后RVA就变成了文件偏移,然后再定位
242+ PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY )((BYTE * )pBuf + exportDirFileOffset );
243+
244+ //解析导出表,这里同理都是RVA
245+ DWORD pRNames = pExportDir -> AddressOfNames ;
246+ DWORD pFNames = RVAtoFileOffset (pRNames , pNtHeader , pSec );
247+ DWORD * pNames = (DWORD * )((PBYTE )pBuf + pFNames );
248+
249+ DWORD pRFunctions = pExportDir -> AddressOfFunctions ;
250+ DWORD pFFunctions = RVAtoFileOffset (pRFunctions , pNtHeader , pSec );
251+ DWORD * pFunctions = (DWORD * )((PBYTE )pBuf + pFFunctions );
252+
253+ WORD pRNameOrdinals = pExportDir -> AddressOfNameOrdinals ;
254+ WORD pFNameOrdinals = RVAtoFileOffset (pRNameOrdinals , pNtHeader , pSec );
255+ WORD * pNameOrdinals = (WORD * )((PBYTE )pBuf + pFFunctions );
256+
257+ // 遍历查找目标函数
258+ DWORD funcRVA = 0 ;
259+ for (DWORD i = 0 ; i < pExportDir -> NumberOfNames ; i ++ ) {
260+ DWORD functionNameRVA = pNames [i ];
261+ DWORD functionNameFileOffset = RVAtoFileOffset (functionNameRVA , pNtHeader , pSec );
262+ const char * pName = (char * )((PBYTE )pBuf + functionNameFileOffset );
263+ if (strcmp (pName , funcName ) == 0 ) {
264+ funcRVA = pFunctions [i ];
265+ break ;
266+ }
267+ }
268+ if (funcRVA == 0 ) {
269+ printf ("\n[-] Function %s not found.\n" , funcName );
270+ return NULL ;
271+ }
272+
273+ DWORD fileOffset = RVAtoFileOffset (funcRVA , pNtHeader , pSec );
274+ return fileOffset ;
275+ }
0 commit comments