<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
LyScript 外掛整合的內建API函數可靈活的實現繞過各類反偵錯保護機制,前段時間釋出的那一篇文章並沒有詳細講解各類反偵錯機制的繞過措施,本次將補充這方面的知識點,運用LyScript實現繞過大多數通用偵錯機制,實現隱藏偵錯程式的目的。
我們以此實現Patches如下函數:
首先第一步我們需要自己封裝實現一個反組合轉機器碼的函數,其作用是當用戶傳入組合列表時,自動將其轉為機器碼並輸出為列表格式。
from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ShellCode = GetOpCode(dbg, ["DB 0x64","mov eax,dword ptr ds:[18]","sub eax,eax","ret"]) print(ShellCode) dbg.close()
輸出效果如下:
PEB結構存在許多反偵錯變數,首先我們需要先將這些變數填充為空。
# ---------------------------------------------- # By: LyShark # Email: me@lyshark.com # Project: https://github.com/lyshark/LyScript # ---------------------------------------------- from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_PEB(dbg): PEB = dbg.get_peb_address(dbg.get_process_id()) if PEB == 0: return 0 # 寫出0 Patching PEB.IsDebugged dbg.write_memory_byte(PEB + 0x2,GetOpCode(dbg,["db 0"])[0]) print("修補程式地址: {}".format(hex(PEB+0x2))) # 寫出0 Patching PEB.ProcessHeap.Flag temp = dbg.read_memory_dword(PEB + 0x18) temp += 0x10 dbg.write_memory_dword(temp, GetOpCode(dbg,["db 0"])[0]) print(("修補程式地址: {}".format(hex(temp)))) # 寫出0 atching PEB.NtGlobalFlag dbg.write_memory_dword(PEB+0x68, 0) print(("修補程式地址: {}".format(hex(PEB+0x68)))) # 迴圈替換 Patch PEB_LDR_DATA 0xFEEEFEEE fill bytes about 3000 of them addr = dbg.read_memory_dword(PEB + 0x0c) while addr != 0: addr += 1 try: b = dbg.read_memory_dword(addr) c = dbg.read_memory_dword(addr + 4) # 僅修補填充執行 print(b) if (b == 0xFEEEFEEE) and (c == 0xFEEEFEEE): dbg.write_memory_dword(addr,0) dbg.write_memory_dword(addr + 4, 0) print("patch") except Exception: break if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() Patch_PEB(dbg) dbg.close()
該函數用於檢測自身是否處於偵錯狀態,其C系列程式碼如下所示,繞過此種方式很簡單,只需要在函數頭部寫出ret指令即可。
#include <Windows.h> #include <stdio.h> int _tmain(int argc, _TCHAR* argv[]) { BOOL ref = IsDebuggerPresent(); printf("是否被偵錯: %d n", ref); getchar(); return 0; }
注意:此Api檢查PEB中的值,因此如果修補PEB,則無需修補Api,這段繞過程式碼如下。
from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_IsDebuggerPresent(dbg): # 得到模組控制程式碼 ispresent = dbg.get_module_from_function("kernel32.dll","IsDebuggerPresent") print(hex(ispresent)) if(ispresent <= 0): print("無法得到模組基地址,請以管理員方式執行偵錯程式.") return 0 # 將反偵錯語句轉為機器碼 ShellCode = GetOpCode(dbg, ["DB 0x64", "mov eax,dword ptr ds:[18]", "sub eax,eax", "ret"]) print(ShellCode) flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(ispresent + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_IsDebuggerPresent(dbg) print("修補程式狀態: {}".format(ref)) dbg.close()
當程式執行後會向IsDebuggerPresent
函數寫出返回,從而實現繞過偵錯的目的。
此Api呼叫ZwQueryInformationProcess
因此通常不需要對兩者進行修補。
from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_CheckRemoteDebuggerPresent(dbg): # 得到模組控制程式碼 ispresent = dbg.get_module_from_function("kernel32.dll","CheckRemoteDebuggerPresent") print(hex(ispresent)) # 將反偵錯語句轉為機器碼 ShellCode = GetOpCode(dbg, [ "mov edi,edi", "push ebp", "mov ebp,esp", "mov eax,[ebp+0xc]", "push 0", "pop dword ptr ds:[eax]", "xor eax,eax", "pop ebp", "ret 8" ] ) print(ShellCode) flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(ispresent + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_CheckRemoteDebuggerPresent(dbg) print("寫出狀態: {}".format(ref)) dbg.close()
寫出效果如下:
GetTickCount返回(retrieve)從作業系統啟動所經過(elapsed)的毫秒數,常用於定時計數,繞過方式只需初始化即可。
from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_GetTickCount(dbg): # 得到模組控制程式碼 ispresent = dbg.get_module_from_function("kernel32.dll","GetTickCount") print(hex(ispresent)) # 將反偵錯語句轉為機器碼 ShellCode = GetOpCode(dbg, [ "mov edx,0x7ffe0000", "sub eax,eax", "add eax,0xB0B1560D", "ret" ] ) print(ShellCode) flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(ispresent + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_GetTickCount(dbg) print("寫出狀態: {}".format(ref)) dbg.close()
寫出效果如下:
此函數打修補程式需要跳轉兩次,原因是因為函數開頭部分無法填充更多指令,需要我們自己來申請空間,並實現跳轉。
# ---------------------------------------------- # By: LyShark # Email: me@lyshark.com # Project: https://github.com/lyshark/LyScript # ---------------------------------------------- from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode # 獲取指定位置前index條指令的長度 def GetOpCodeSize(dbg,address,index): ref_size = 0 dasm = dbg.get_disasm_code(address,index) for index in dasm: count = dbg.assemble_code_size(index.get("opcode")) ref_size += count return ref_size def Patch_ZwQueryInformationProcess(dbg): # 得到模組控制程式碼 ispresent = dbg.get_module_from_function("ntdll.dll","ZwQueryInformationProcess") print(hex(ispresent)) create_address = dbg.create_alloc(1024) print("分配空間: {}".format(hex(create_address))) # 將反偵錯語句轉為機器碼 ShellCode = GetOpCode(dbg, [ "cmp dword [esp + 8],7", "DB 0x74", "DB 0x06", f"push {hex(ispresent)}", "ret", "mov eax,dword [esp +0x0c]", "push 0", "pop dword [eax]", "xor eax,eax", "ret 14" ] ) print(ShellCode) # 把shellcode寫出到自己分配的堆中 flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(create_address + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 # 填充跳轉位置 jmp_shellcode = GetOpCode(dbg, [ f"push {hex(create_address)}", "ret" ] ) for index in range(0,len(jmp_shellcode)): flag = dbg.write_memory_byte(ispresent + index,jmp_shellcode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_ZwQueryInformationProcess(dbg) print("修補程式狀態: {}".format(ref)) dbg.close()
這段程式碼執行後,首先會申請記憶體,然後將特定的一段機器碼寫出到此記憶體中。
記憶體寫出以後,再將函數頭部替換為跳轉,這樣一來當函數被呼叫,也就自動轉向了。
FindWindow函數功能是取表單控制程式碼,有AW與Ex系列,使用同上方法替代即可。
# ---------------------------------------------- # By: LyShark # Email: me@lyshark.com # Project: https://github.com/lyshark/LyScript # ---------------------------------------------- from LyScript32 import MyDebug import ctypes # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode def Patch_FindWindow(dbg): # 得到模組控制程式碼 FindWindowA = dbg.get_module_from_function("user32.dll","FindWindowA") FindWindowW = dbg.get_module_from_function("user32.dll","FindWindowW") FindWindowExA = dbg.get_module_from_function("user32.dll","FindWindowExA") FindWindowExW = dbg.get_module_from_function("user32.dll","FindWindowExW") print("A = {} w = {} exA = {} exW = {}".format(hex(FindWindowA),hex(FindWindowW),hex(FindWindowExA),hex(FindWindowExW))) # 將反偵錯語句轉為機器碼 ShellCode = GetOpCode(dbg, [ "xor eax,eax", "ret 0x8", ] ) ShellCodeEx = GetOpCode(dbg, [ "xor eax,eax", "ret 0x10", ] ) # 寫出 flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(FindWindowA + index,ShellCode[index]) flag = dbg.write_memory_byte(FindWindowW + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 for index in range(0,len(ShellCodeEx)): flag = dbg.write_memory_byte(FindWindowExA + index,ShellCodeEx[index]) flag = dbg.write_memory_byte(FindWindowExW + index,ShellCodeEx[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_FindWindow(dbg) print("修補程式狀態: {}".format(ref)) dbg.close()
修補程式應用會分別替換四個函數。
列舉表單的修補程式與上方程式碼一致,此處就不再分析了。
如下案例,實現了在列舉表單過程中實現彈窗,並不影響表單的列舉。
from LyScript32 import MyDebug # 傳入組合程式碼,得到對應機器碼 def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("組合程式碼佔用位元組: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # 傳入組合機器碼得到機器碼列表 def GetOpCode(dbg, Code): ShellCode = [] for index in Code: ref = get_opcode_from_assemble(dbg,index) for opcode in ref: ShellCode.append(opcode) return ShellCode # 獲取指定位置前index條指令的長度 def GetOpCodeSize(dbg,address,index): ref_size = 0 dasm = dbg.get_disasm_code(address,index) for index in dasm: count = dbg.assemble_code_size(index.get("opcode")) ref_size += count return ref_size def Patch_EnumWindows(dbg): # 得到模組控制程式碼 address = dbg.get_module_from_function("user32.dll","EnumWindows") print(hex(address)) msg_box = dbg.get_module_from_function("user32.dll","MessageBoxA") print(hex(msg_box)) create_address = dbg.create_alloc(1024) print("分配空間: {}".format(hex(create_address))) # 找call地址,找到後取出他的記憶體地址 dasm_list = dbg.get_disasm_code(address,20) call_addr = 0 call_next_addr = 0 for index in range(0,len(dasm_list)): # 如果找到了call,取出call地址以及下一條地址 if dasm_list[index].get("opcode").split(" ")[0] == "call": call_addr = dasm_list[index].get("addr") call_next_addr = dasm_list[index+1].get("addr") print("call = {} call_next = {}".format(hex(call_addr),hex(call_next_addr))) # 將反偵錯語句轉為機器碼 ShellCode = GetOpCode(dbg, [ "push 0", "push 0", "push 0", "push 0", f"call {hex(msg_box)}", "mov eax,1", "pop ebp", "ret 10", f"call {hex(call_addr)}", "pop ebp", "ret 8" ] ) print(ShellCode) # 把shellcode寫出到自己分配的堆中 flag = 0 for index in range(0,len(ShellCode)): flag = dbg.write_memory_byte(create_address + index,ShellCode[index]) if flag: flag = 1 else: flag = 0 # 填充跳轉位置 jmp_shellcode = GetOpCode(dbg, [ f"push {hex(create_address)}", "ret" ] ) for index in range(0,len(jmp_shellcode)): flag = dbg.write_memory_byte(call_addr + index,jmp_shellcode[index]) if flag: flag = 1 else: flag = 0 return flag if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() ref = Patch_EnumWindows(dbg) dbg.close()
輸出效果如下:
以上就是LyScript實現Hook隱藏偵錯程式的方法詳解的詳細內容,更多關於LyScript Hook隱藏偵錯程式的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45