1+ ;
2+ ; Copyright © 2019 Odzhan. All Rights Reserved.
3+ ;
4+ ; Redistribution and use in source and binary forms, with or without
5+ ; modification, are permitted provided that the following conditions are
6+ ; met:
7+ ;
8+ ; 1. Redistributions of source code must retain the above copyright
9+ ; notice, this list of conditions and the following disclaimer.
10+ ;
11+ ; 2. Redistributions in binary form must reproduce the above copyright
12+ ; notice, this list of conditions and the following disclaimer in the
13+ ; documentation and/or other materials provided with the distribution.
14+ ;
15+ ; 3. The name of the author may not be used to endorse or promote products
16+ ; derived from this software without specific prior written permission.
17+ ;
18+ ; THIS SOFTWARE IS PROVIDED BY AUTHORS "AS IS" AND ANY EXPRESS OR
19+ ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+ ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+ ; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22+ ; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+ ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+ ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25+ ; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26+ ; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27+ ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+ ; POSSIBILITY OF SUCH DAMAGE.
29+ ;
30+ ; In-Memory execution of VBScript/JScript using 395 bytes of x86 assembly
31+ ; Odzhan
32+
33+ %include "ax.inc"
34+
35+ %define VBS
36+
37+ bits 32
38+
39+ %ifndef BIN
40+ global run_scriptx
41+ global _run_scriptx
42+ %endif
43+
44+ run_scriptx:
45+ _run_scriptx:
46+ pop ecx ; ecx = return address
47+ pop eax ; eax = script parameter
48+ push ecx ; save return address
49+ cdq ; edx = 0
50+ ; allocate 128KB of stack.
51+ push 32 ; ecx = 32
52+ pop ecx
53+ mov dh , 16 ; edx = 4096
54+ pushad ; save all registers
55+ xchg eax , esi ; esi = script
56+ alloc_mem:
57+ sub esp , edx ; subtract size of page
58+ test [ esp ], esp ; stack probe
59+ loop alloc_mem ; continue for 32 pages
60+ mov edi , esp ; edi = memory
61+ xor eax , eax
62+ utf8_to_utf16: ; YMMV. Prone to a stack overflow.
63+ cmp byte [ esi ], al ; ? [esi] == 0
64+ movsb ; [edi] = [esi], edi++, esi++
65+ stosb ; [edi] = 0, edi++
66+ jnz utf8_to_utf16 ;
67+ stosd ; store 4 nulls at end
68+ and edi , - 4 ; align by 4 bytes
69+ call init_api ; load address of invoke_api onto stack
70+ ; *******************************
71+ ; INPUT: eax contains hash of API
72+ ; Assumes DLL already loaded
73+ ; No support for resolving by ordinal or forward references
74+ ; *******************************
75+ invoke_api:
76+ pushad
77+ push TEB.ProcessEnvironmentBlock
78+ pop ecx
79+ mov eax , [ fs : ecx ]
80+ mov eax , [ eax + PEB.Ldr ]
81+ mov edi , [ eax + PEB_LDR_DATA.InLoadOrderModuleList + LIST_ENTRY.Flink ]
82+ jmp get_dll
83+ next_dll:
84+ mov edi , [ edi + LDR_DATA_TABLE_ENTRY.InLoadOrderLinks + LIST_ENTRY.Flink ]
85+ get_dll:
86+ mov ebx , [ edi + LDR_DATA_TABLE_ENTRY.DllBase ]
87+ mov eax , [ ebx + IMAGE_DOS_HEADER.e_lfanew ]
88+ ; ecx = IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
89+ mov ecx , [ ebx + eax + IMAGE_NT_HEADERS.OptionalHeader + \
90+ IMAGE_OPTIONAL_HEADER32.DataDirectory + \
91+ IMAGE_DIRECTORY_ENTRY_EXPORT * IMAGE_DATA_DIRECTORY_size + \
92+ IMAGE_DATA_DIRECTORY.VirtualAddress ]
93+ jecxz next_dll
94+ ; esi = offset IMAGE_EXPORT_DIRECTORY.NumberOfNames
95+ lea esi , [ ebx + ecx + IMAGE_EXPORT_DIRECTORY.NumberOfNames ]
96+ lodsd
97+ xchg eax , ecx
98+ jecxz next_dll ; skip if no names
99+ ; ebp = IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
100+ lodsd
101+ add eax , ebx ; ebp = RVA2VA(eax, ebx)
102+ xchg eax , ebp ;
103+ ; edx = IMAGE_EXPORT_DIRECTORY.AddressOfNames
104+ lodsd
105+ add eax , ebx ; edx = RVA2VA(eax, ebx)
106+ xchg eax , edx ;
107+ ; esi = IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
108+ lodsd
109+ add eax , ebx ; esi = RVA2VA(eax, ebx)
110+ xchg eax , esi
111+ get_name:
112+ pushad
113+ mov esi , [ edx + ecx * 4 - 4 ] ; esi = AddressOfNames[ecx-1]
114+ add esi , ebx ; esi = RVA2VA(esi, ebx)
115+ xor eax , eax ; eax = 0
116+ cdq ; h = 0
117+ hash_name:
118+ lodsb
119+ add edx , eax
120+ ror edx , 8
121+ dec eax
122+ jns hash_name
123+ cmp edx , [ esp + _eax + pushad_t_size ] ; hashes match?
124+ popad
125+ loopne get_name ; --ecx && edx != hash
126+ jne next_dll ; get next DLL
127+ movzx eax , word [ esi + ecx * 2 ] ; eax = AddressOfNameOrdinals[ecx]
128+ add ebx , [ ebp + eax * 4 ] ; ecx = base + AddressOfFunctions[eax]
129+ mov [ esp + _eax ], ebx
130+ popad ; restore all
131+ jmp eax
132+ _ds_section:
133+ ; ---------------------
134+ db "ole32" , 0 , 0 , 0
135+ co_init:
136+ db "CoInitializeEx" , 0
137+ co_init_len equ $ - co_init
138+ co_create:
139+ db "CoCreateInstance" , 0
140+ co_create_len equ $ - co_create
141+ ; IID_IActiveScript
142+ ; IID_IActiveScriptParse32 +1
143+ dd 0xbb1a2ae1
144+ dw 0xa4f9 , 0x11cf
145+ db 0x8f , 0x20 , 0x00 , 0x80 , 0x5f , 0x2c , 0xd0 , 0x64
146+ %ifdef VBS
147+ ; CLSID_VBScript
148+ dd 0xB54F3741
149+ dw 0x5B07 , 0x11cf
150+ db 0xA4 , 0xB0 , 0x00 , 0xAA , 0x00 , 0x4A , 0x55 , 0xE8
151+ %else
152+ ; CLSID_JScript
153+ dd 0xF414C260
154+ dw 0x6AC0 , 0x11CF
155+ db 0xB6 , 0xD1 , 0x00 , 0xAA , 0x00 , 0xBB , 0xBB , 0x58
156+ %endif
157+ _QueryInterface:
158+ mov eax , E_NOTIMPL ; return E_NOTIMPL
159+ retn 3 * 4
160+ _AddRef:
161+ _Release:
162+ pop eax ; return S_OK
163+ push eax
164+ push eax
165+ _GetLCID:
166+ _GetItemInfo:
167+ _GetDocVersionString:
168+ pop eax ; return S_OK
169+ push eax
170+ push eax
171+ _OnScriptTerminate:
172+ xor eax , eax ; return S_OK
173+ retn 3 * 4
174+ _OnStateChange:
175+ _OnScriptError:
176+ jmp _GetDocVersionString
177+ _OnEnterScript:
178+ _OnLeaveScript:
179+ jmp _Release
180+ init_api:
181+ pop ebp
182+ lea esi , [ ebp + (_ds_section - invoke_api) ]
183+
184+ ; LoadLibrary("ole32");
185+ push esi ; "ole32", 0
186+ mov eax , 0xFA183D4A ; eax = hash("LoadLibraryA")
187+ call ebp ; invoke_api(eax)
188+ xchg ebx , eax ; ebp = base of ole32
189+ lodsd ; skip "ole32"
190+ lodsd
191+
192+ ; _CoInitializeEx = GetProcAddress(ole32, "CoInitializeEx");
193+ mov eax , 0x4AAC90F7 ; eax = hash("GetProcAddress")
194+ push eax ; save eax/hash
195+ push esi ; esi = "CoInitializeEx"
196+ push ebx ; base of ole32
197+ call ebp ; invoke_api(eax)
198+
199+ ; 1. _CoInitializeEx(NULL, COINIT_MULTITHREADED);
200+ cdq ; edx = 0
201+ push edx ; COINIT_MULTITHREADED
202+ push edx ; NULL
203+ call eax ; CoInitializeEx
204+
205+ add esi , co_init_len ; skip "CoInitializeEx", 0
206+
207+ ; _CoCreateInstance = GetProcAddress(ole32, "CoCreateInstance");
208+ pop eax ; eax = hash("GetProcAddress")
209+ push esi ; "CoCreateInstance"
210+ push ebx ; base of ole32
211+ call ebp ; invoke_api
212+
213+ add esi , co_create_len ; skip "CoCreateInstance", 0
214+
215+ ; 2. _CoCreateInstance(
216+ ; &langId, 0, CLSCTX_INPROC_SERVER,
217+ ; &IID_IActiveScript, (void **)&engine);
218+ push edi ; &engine
219+ scasd ; skip engine
220+ mov ebx , edi ; ebx = &parser
221+ push edi ; &IID_IActiveScript
222+ movsd
223+ movsd
224+ movsd
225+ movsd
226+ push CLSCTX_INPROC_SERVER
227+ push 0 ;
228+ push esi ; &CLSID_VBScript or &CLSID_JScript
229+ call eax ; _CoCreateInstance
230+
231+ ; 3. Query engine for script parser
232+ ; engine->lpVtbl->QueryInterface(
233+ ; engine, &IID_IActiveScriptParse,
234+ ; (void **)&parser);
235+ push edi ; &parser
236+ push ebx ; &IID_IActiveScriptParse32
237+ inc dword [ ebx ] ; add 1 for IActiveScriptParse32
238+ mov esi , [ ebx - 4 ] ; esi = engine
239+ push esi ; engine
240+ mov eax , [ esi ] ; eax = engine->lpVtbl
241+ call dword [ eax + IUnknownVtbl.QueryInterface ]
242+
243+ ; 4. Initialize parser
244+ ; parser->lpVtbl->InitNew(parser);
245+ mov ebx , [ edi ] ; ebx = parser
246+ push ebx ; parser
247+ mov eax , [ ebx ] ; eax = parser->lpVtbl
248+ call dword [ eax + IActiveScriptParse32Vtbl.InitNew ]
249+
250+ ; 5. Initialize IActiveScriptSite
251+ lea eax , [ ebp + (_QueryInterface - invoke_api) ]
252+ push edi ; save pointer to IActiveScriptSiteVtbl
253+ stosd ; vft.QueryInterface = (LPVOID)QueryInterface;
254+ add eax , _AddRef - _QueryInterface
255+ stosd ; vft.AddRef = (LPVOID)AddRef;
256+ stosd ; vft.Release = (LPVOID)Release;
257+ add eax , _GetLCID - _Release
258+ stosd ; vft.GetLCID = (LPVOID)GetLCID;
259+ stosd ; vft.GetItemInfo = (LPVOID)GetItemInfo;
260+ stosd ; vft.GetDocVersionString = (LPVOID)GetDocVersionString;
261+ add eax , _OnScriptTerminate - _GetDocVersionString
262+ stosd ; vft.OnScriptTerminate = (LPVOID)OnScriptTerminate;
263+ add eax , _OnStateChange - _OnScriptTerminate
264+ stosd ; vft.OnStateChange = (LPVOID)OnStateChange;
265+ stosd ; vft.OnScriptError = (LPVOID)OnScriptError;
266+ inc eax
267+ inc eax
268+ stosd ; vft.OnEnterScript = (LPVOID)OnEnterScript;
269+ stosd ; vft.OnLeaveScript = (LPVOID)OnLeaveScript;
270+ pop eax ; eax = &vft
271+ mov ebp , edi ; ebp = &IMyActiveScriptSite
272+ stosd ; IActiveScriptSite.lpVtbl = &vft
273+ xor eax , eax
274+ stosd ; IActiveScriptSiteWindow.lpVtbl = NULL
275+
276+ ; 6. Set script site
277+ ; engine->lpVtbl->SetScriptSite(
278+ ; engine, (IActiveScriptSite *)&mas);
279+ push ebp ; &IMyActiveScriptSite
280+ push esi ; engine
281+ mov eax , [ esi ]
282+ call dword [ eax + IActiveScriptVtbl.SetScriptSite ]
283+
284+ ; 7. Parse our script
285+ ; parser->lpVtbl->ParseScriptText(
286+ ; parser, cs, 0, 0, 0, 0, 0, 0, 0, 0);
287+ mov ebp , esp
288+ cdq
289+ push 8
290+ pop ecx
291+ init_parse:
292+ push edx
293+ loop init_parse
294+ push ebp
295+ push ebx
296+ mov eax , [ ebx ]
297+ call dword [ eax + IActiveScriptParse32Vtbl.ParseScriptText ]
298+
299+ ; 8. Run script
300+ ; engine->lpVtbl->SetScriptState(
301+ ; engine, SCRIPTSTATE_CONNECTED);
302+ push SCRIPTSTATE_CONNECTED
303+ push esi
304+ mov eax , [ esi ]
305+ call dword [ eax + IActiveScriptVtbl.SetScriptState ]
306+
307+ ; 9. cleanup
308+ ; parser->lpVtbl->Release(parser);
309+ push ebx
310+ mov eax , [ ebx ]
311+ call dword [ eax + IUnknownVtbl.Release ]
312+
313+ ; engine->lpVtbl->Close(engine);
314+ push esi ; engine
315+ push esi ; engine
316+ lodsd ; eax = lpVtbl
317+ xchg eax , edi
318+ call dword [ edi + IActiveScriptVtbl.Close ]
319+ ; engine->lpVtbl->Release(engine);
320+ call dword [ edi + IUnknownVtbl.Release ]
321+
322+ inc eax ; eax = 4096 * 32
323+ shl eax , 17
324+ add esp , eax
325+ popad
326+ ret
327+
328+
0 commit comments