Skip to content

Commit c20141c

Browse files
committed
Adding error reporting for injection via k32 imports
1 parent 3d6517f commit c20141c

File tree

1 file changed

+46
-7
lines changed

1 file changed

+46
-7
lines changed

windows/injection.py

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)