@@ -105,13 +105,38 @@ def perform_manual_getproc_loadlib_64(target, dll_name):
105105 raise InjectionFailedError ("Injection of <{0}> failed" .format (dll_name ))
106106 return True
107107
108- def generate_simple_LoadLibraryW_64 (load_libraryW , remote_store ):
108+ def generate_simple_LoadLibraryW_32_with_error (k32 ):
109+ """A shellcode that execute LoadLibraryW(param) and returns the value.
110+ If LoadLibraryW fails -> returns (GetLastError | 0x10000000)
111+
112+ As a valid 32b modules will never be in >=0x80000000,
113+ this allow to determine if the call was successful of not"""
114+ load_libraryW = k32 .pe .exports ["LoadLibraryW" ]
115+ GetLastError = k32 .pe .exports ["GetLastError" ]
116+
117+ code = x86 .MultipleInstr ()
118+ code += x86 .Mov ("EAX" , x86 .mem ("[ESP + 4]" ))
119+ code += x86 .Push ("EAX" )
120+ code += x86 .Mov ("EAX" , load_libraryW )
121+ code += x86 .Call ("EAX" )
122+ code += x86 .Cmp ("EAX" , 0 )
123+ code += x86 .Jnz (":end" )
124+ code += x86 .Mov ("EAX" , GetLastError )
125+ code += x86 .Call ("EAX" )
126+ code += x86 .Add ("EAX" , 0x80000000 )
127+ code += x86 .Label (":end" )
128+ code += x86 .Ret ()
129+ return code .get_code ()
130+
131+ def generate_simple_LoadLibraryW_64 (load_libraryW , GetLastError , remote_store ):
109132 code = RemoteLoadLibrayStub = x64 .MultipleInstr ()
110133 code += x64 .Mov ("RAX" , load_libraryW )
111134 code += (x64 .Push ("RDI" ) * 5 ) # Prepare stack
112135 code += x64 .Call ("RAX" )
113- code += (x64 .Pop ("RDI" ) * 5 ) # Clean stack
114136 code += x64 .Mov (x64 .deref (remote_store ), "RAX" )
137+ code += x64 .Mov ("RAX" , GetLastError )
138+ code += x64 .Call ("RAX" )
139+ code += (x64 .Pop ("RDI" ) * 5 ) # Clean stack
115140 code += x64 .Ret ()
116141 return RemoteLoadLibrayStub .get_code ()
117142
@@ -138,15 +163,25 @@ def load_dll_in_remote_process(target, dll_path):
138163 k32 = k32 [0 ]
139164 try :
140165 load_libraryW = k32 .pe .exports ["LoadLibraryW" ]
166+ GetLastError = k32 .pe .exports ["GetLastError" ]
141167 except KeyError :
142168 raise ValueError ("Kernel32 have no export <LoadLibraryA> (wtf)" )
143169
144170 with target .allocated_memory (0x1000 ) as addr :
145171 if target .bitness == 32 :
146- target .write_memory (addr , (dll_path + "\x00 " ).encode ('utf-16le' ))
147- t = target .create_thread (load_libraryW , addr )
172+ shellcode32 = generate_simple_LoadLibraryW_32_with_error (k32 )
173+ encoded_dll_name = (dll_path + "\x00 " ).encode ('utf-16le' )
174+ paramaddr = addr
175+ target .write_memory (addr , encoded_dll_name )
176+ shellcode_addr = addr + len (encoded_dll_name )
177+ target .write_memory (shellcode_addr , shellcode32 )
178+ t = target .create_thread (shellcode_addr , paramaddr )
148179 t .wait ()
149- module_baseaddr = t .exit_code
180+ exit_code = module_baseaddr = t .exit_code
181+ if module_baseaddr & 0x80000000 :
182+ # Not a possible userland addr -> its a GetLastError()
183+ module_baseaddr = None
184+ exit_code = exit_code & 0x7fffffff
150185 else :
151186 # For 64b target we need a special stub as the return value of
152187 # load_libraryW does not fit in t.exit_code (DWORD)
@@ -158,14 +193,18 @@ def load_dll_in_remote_process(target, dll_path):
158193 param_addr = addr
159194 addr += len (full_dll_name )
160195 shellcode_addr = addr
161- shellcode = generate_simple_LoadLibraryW_64 (load_libraryW , retval_addr )
196+ shellcode = generate_simple_LoadLibraryW_64 (load_libraryW , GetLastError , retval_addr )
162197 target .write_memory (shellcode_addr , shellcode )
163198 t = target .create_thread (shellcode_addr , param_addr )
164199 t .wait ()
200+ exit_code = t .exit_code
165201 module_baseaddr = target .read_ptr (retval_addr )
166202
167203 if not module_baseaddr :
168- raise InjectionFailedError (u"Injection of <{0}> failed" .format (dll_path ))
204+ real_error = ctypes .WinError (exit_code )
205+ myexc = InjectionFailedError (u"Injection of <{0}> failed due to error <{1}> in injected process" .format (dll_path , str (real_error )))
206+ myexc .__cause__ = real_error
207+ raise myexc
169208 dbgprint ("DLL Injected via LoadLibray" , "DLLINJECT" )
170209 # Cannot return the full return value of load_libraryW in 64b target.. (exit_code is a DWORD)
171210 return module_baseaddr
0 commit comments