mirror of
https://github.com/qilingframework/qiling.git
synced 2026-10-12 11:29:57 +00:00
212 lines
7.1 KiB
Python
212 lines
7.1 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
|
#
|
|
|
|
from unicorn import UcError
|
|
|
|
import sys
|
|
sys.path.append("..")
|
|
|
|
from qiling import Qiling
|
|
from qiling.const import QL_VERBOSE
|
|
from qiling.os.const import POINTER, DWORD, STRING, HANDLE
|
|
from qiling.os.windows import utils
|
|
from qiling.os.windows.api import *
|
|
from qiling.os.windows.fncc import *
|
|
from qiling.os.windows.dlls.kernel32.fileapi import _CreateFile
|
|
|
|
def init_unseen_symbols(ql: Qiling, address: int, name: str, ordinal: int, dll_name: str):
|
|
ql.loader.import_symbols[address] = {
|
|
"name": name,
|
|
"ordinal": ordinal,
|
|
"dll": dll_name.partition('.')[0]
|
|
}
|
|
|
|
ql.loader.import_address_table[dll_name][name] = address
|
|
|
|
if ordinal != 0:
|
|
ql.loader.import_address_table[dll_name][ordinal] = address
|
|
|
|
|
|
# HANDLE CreateThread(
|
|
# LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
# SIZE_T dwStackSize,
|
|
# LPTHREAD_START_ROUTINE lpStartAddress,
|
|
# __drv_aliasesMem LPVOID lpParameter,
|
|
# DWORD dwCreationFlags,
|
|
# LPDWORD lpThreadId
|
|
# );
|
|
@winsdkapi(cc=STDCALL, params={
|
|
'lpThreadAttributes' : LPSECURITY_ATTRIBUTES,
|
|
'dwStackSize' : SIZE_T,
|
|
'lpStartAddress' : LPTHREAD_START_ROUTINE,
|
|
'lpParameter' : LPVOID,
|
|
'dwCreationFlags' : DWORD,
|
|
'lpThreadId' : LPDWORD
|
|
})
|
|
def hook_CreateThread(ql: Qiling, address: int, params):
|
|
# set thread handle
|
|
return 1
|
|
|
|
# HANDLE CreateFileA(
|
|
# LPCSTR lpFileName,
|
|
# DWORD dwDesiredAccess,
|
|
# DWORD dwShareMode,
|
|
# LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
# DWORD dwCreationDisposition,
|
|
# DWORD dwFlagsAndAttributes,
|
|
# HANDLE hTemplateFile
|
|
# );
|
|
@winsdkapi(cc=STDCALL, params={
|
|
'lpFileName' : LPCSTR,
|
|
'dwDesiredAccess' : DWORD,
|
|
'dwShareMode' : DWORD,
|
|
'lpSecurityAttributes' : LPSECURITY_ATTRIBUTES,
|
|
'dwCreationDisposition' : DWORD,
|
|
'dwFlagsAndAttributes' : DWORD,
|
|
'hTemplateFile' : HANDLE
|
|
})
|
|
def hook_CreateFileA(ql: Qiling, address: int, params):
|
|
lpFileName = params["lpFileName"]
|
|
if lpFileName.startswith("\\\\.\\"):
|
|
if ql.amsint32_driver:
|
|
return 0x13371337
|
|
else:
|
|
return (-1)
|
|
else:
|
|
ret = _CreateFile(ql, address, params, "CreateFileA")
|
|
return ret
|
|
|
|
def _WriteFile(ql: Qiling, address: int, params):
|
|
ret = 1
|
|
hFile = params["hFile"]
|
|
lpBuffer = params["lpBuffer"]
|
|
nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"]
|
|
lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"]
|
|
#lpOverlapped = params["lpOverlapped"]
|
|
|
|
if hFile == 0xfffffff5:
|
|
s = ql.mem.read(lpBuffer, nNumberOfBytesToWrite)
|
|
ql.os.stdout.write(s)
|
|
ql.os.utils.string_appearance(s.decode())
|
|
ql.mem.write(lpNumberOfBytesWritten, ql.pack(nNumberOfBytesToWrite))
|
|
else:
|
|
f = ql.os.handle_manager.get(hFile)
|
|
if f is None:
|
|
# Invalid handle
|
|
ql.os.last_error = 0xffffffff
|
|
return 0
|
|
else:
|
|
f = f.obj
|
|
buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite)
|
|
f.write(bytes(buffer))
|
|
ql.mem.write(lpNumberOfBytesWritten, ql.pack32(nNumberOfBytesToWrite))
|
|
return ret
|
|
|
|
@winsdkapi(cc=STDCALL, params={
|
|
'hFile' : HANDLE,
|
|
'lpBuffer' : LPCVOID,
|
|
'nNumberOfBytesToWrite' : DWORD,
|
|
'lpNumberOfBytesWritten' : LPDWORD,
|
|
'lpOverlapped' : LPOVERLAPPED
|
|
})
|
|
def hook_WriteFile(ql: Qiling, address: int, params):
|
|
hFile = params["hFile"]
|
|
lpBuffer = params["lpBuffer"]
|
|
nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"]
|
|
lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"]
|
|
if hFile == 0x13371337:
|
|
buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite)
|
|
try:
|
|
r, nNumberOfBytesToWrite = utils.io_Write(ql.amsint32_driver, buffer)
|
|
ql.mem.write(lpNumberOfBytesWritten, ql.pack32(nNumberOfBytesToWrite))
|
|
except Exception as e:
|
|
ql.log.exception("")
|
|
print("Exception = %s" % str(e))
|
|
r = 1
|
|
if r:
|
|
return 1
|
|
else:
|
|
return 0
|
|
else:
|
|
return _WriteFile(ql, address, params)
|
|
|
|
|
|
# BOOL StartServiceA(
|
|
# SC_HANDLE hService,
|
|
# DWORD dwNumServiceArgs,
|
|
# LPCSTR *lpServiceArgVectors
|
|
# );
|
|
@winsdkapi(cc=STDCALL, params={
|
|
'hService' : SC_HANDLE,
|
|
'dwNumServiceArgs' : DWORD,
|
|
'lpServiceArgVectors' : POINTER
|
|
})
|
|
def hook_StartServiceA(ql: Qiling, address: int, params):
|
|
try:
|
|
hService = params["hService"]
|
|
service_handle = ql.os.handle_manager.get(hService)
|
|
if service_handle.name == "amsint32":
|
|
if service_handle.name in ql.os.services:
|
|
service_path = ql.os.services[service_handle.name]
|
|
service_path = ql.os.path.transform_to_real_path(service_path)
|
|
ql.amsint32_driver = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG)
|
|
init_unseen_symbols(ql.amsint32_driver, ql.amsint32_driver.loader.dlls["ntoskrnl.exe"]+0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe")
|
|
#ql.amsint32_driver.debugger= ":9999"
|
|
try:
|
|
ql.amsint32_driver.load()
|
|
return 1
|
|
except UcError as e:
|
|
print("Load driver error: ", e)
|
|
return 0
|
|
else:
|
|
return 0
|
|
else:
|
|
return 1
|
|
except Exception as e:
|
|
ql.log.exception("")
|
|
print (e)
|
|
|
|
|
|
def hook_stop_address(ql):
|
|
print(" >>>> Stop address: 0x%08x" % ql.reg.arch_pc)
|
|
ql.emu_stop()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG, libcache=True)
|
|
|
|
# for this module
|
|
ql.amsint32_driver = None
|
|
|
|
# emulate some Windows API
|
|
ql.set_api("CreateThread", hook_CreateThread)
|
|
ql.set_api("CreateFileA", hook_CreateFileA)
|
|
ql.set_api("WriteFile", hook_WriteFile)
|
|
ql.set_api("StartServiceA", hook_StartServiceA)
|
|
#init sality
|
|
ql.hook_address(hook_stop_address, 0x40EFFB)
|
|
ql.run()
|
|
# run driver thread
|
|
|
|
# execution is about to resume from 0x4053B2, which essentially jumps to ExitThread (kernel32.dll).
|
|
# Set ExitThread exit code to 0
|
|
ql.os.fcall = ql.os.fcall_select(STDCALL)
|
|
ql.os.fcall.writeParams(((DWORD, 0),))
|
|
|
|
ql.hook_address(hook_stop_address, 0x4055FA)
|
|
ql.run(0x4053B2)
|
|
ql.log.info("test kill thread")
|
|
if ql.amsint32_driver:
|
|
utils.io_Write(ql.amsint32_driver, ql.pack32(0xdeadbeef))
|
|
|
|
# TODO: Should stop at 0x10423, but for now just stop at 0x0001066a
|
|
ql.amsint32_driver.hook_address(hook_stop_address, 0x0001066a)
|
|
|
|
# TODO: not sure whether this one is really STDCALL
|
|
ql.amsint32_driver.os.fcall = ql.amsint32_driver.os.fcall_select(STDCALL)
|
|
ql.amsint32_driver.os.fcall.writeParams(((DWORD, 0),))
|
|
|
|
ql.amsint32_driver.run(begin=0x102D0)
|