網站首頁 編程語言 正文
LyScript 針對內存讀寫函數的封裝功能并不多,只提供了內存讀取和內存寫入函數的封裝,本篇文章將繼續對API進行封裝,實現一些在軟件逆向分析中非常實用的功能,例如內存交換,內存區域對比,磁盤與內存鏡像比較,特征碼檢索等功能。
LyScript項目地址:https://github.com/lyshark/LyScript
內存區域交換
實現被加載程序內特定一塊內存區域的交換,該方法實現原理就是兩個變量之間的交換,只是在交換時需要逐個字節進行,調用read_memory_byte()
函數實現起了很容易。
from LyScript32 import MyDebug # 交換兩個內存區域 def memory_xchage(dbg,memory_ptr_x,memory_ptr_y,bytes): ref = False for index in range(0,bytes): # 讀取兩個內存區域 read_byte_x = dbg.read_memory_byte(memory_ptr_x + index) read_byte_y = dbg.read_memory_byte(memory_ptr_y + index) # 交換內存 ref = dbg.write_memory_byte(memory_ptr_x + index,read_byte_y) ref = dbg.write_memory_byte(memory_ptr_y + index, read_byte_x) return ref if __name__ == "__main__": dbg = MyDebug() dbg.connect() eip = dbg.get_register("eip") # 內存交換 flag = memory_xchage(dbg, 6815744,6815776,4) print("內存交換狀態: {}".format(flag)) dbg.close()
PE文件頭節點交換后如下:
內存區域對比
可用于對比該進程內存中的特定一塊區域的差異,返回是列表中的字典形式,分別傳入對比內存x,y以及需要對比的內存長度,此處建議不要超過1024字節。
from LyScript32 import MyDebug # 對比兩個內存區域 def memory_cmp(dbg,memory_ptr_x,memory_ptr_y,bytes): cmp_memory = [] for index in range(0,bytes): item = {"addr":0, "x": 0, "y": 0} # 讀取兩個內存區域 read_byte_x = dbg.read_memory_byte(memory_ptr_x + index) read_byte_y = dbg.read_memory_byte(memory_ptr_y + index) if read_byte_x != read_byte_y: item["addr"] = memory_ptr_x + index item["x"] = read_byte_x item["y"] = read_byte_y cmp_memory.append(item) return cmp_memory if __name__ == "__main__": dbg = MyDebug() dbg.connect() eip = dbg.get_register("eip") # 內存對比 cmp_ref = memory_cmp(dbg, 6815744,6815776,4) for index in range(0,len(cmp_ref)): print("地址: 0x{:08X} -> X: 0x{:02x} -> y: 0x{:02x}".format(cmp_ref[index].get("addr"),cmp_ref[index].get("x"),cmp_ref[index].get("y"))) dbg.close()
對比特定內存區域,返回差異字節地址:
內存與磁盤機器碼比較
通過調用read_memory_byte()
函數,或者open()
打開文件,等就可以得到程序磁盤與內存中特定位置的機器碼參數,然后通過對每一個列表中的字節進行比較,就可得到特定位置下磁盤與內存中的數據是否一致的判斷。
#coding: utf-8 import binascii,os,sys from LyScript32 import MyDebug # 得到程序的內存鏡像中的機器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數據 char = dbg.read_memory_byte(address + index) count = count + 1 if count % 16 == 0: if (char) < 16: print("0" + hex((char))[2:]) ref_memory_list.append("0" + hex((char))[2:]) else: print(hex((char))[2:]) ref_memory_list.append(hex((char))[2:]) else: if (char) < 16: print("0" + hex((char))[2:] + " ",end="") ref_memory_list.append("0" + hex((char))[2:]) else: print(hex((char))[2:] + " ",end="") ref_memory_list.append(hex((char))[2:]) return ref_memory_list # 讀取程序中的磁盤鏡像中的機器碼 def get_file_hex_ascii(path,offset,len): count = 0 ref_file_list = [] with open(path, "rb") as fp: # file_size = os.path.getsize(path) fp.seek(offset) for item in range(offset,offset + len): char = fp.read(1) count = count + 1 if count % 16 == 0: if ord(char) < 16: print("0" + hex(ord(char))[2:]) ref_file_list.append("0" + hex(ord(char))[2:]) else: print(hex(ord(char))[2:]) ref_file_list.append(hex(ord(char))[2:]) else: if ord(char) < 16: print("0" + hex(ord(char))[2:] + " ", end="") ref_file_list.append("0" + hex(ord(char))[2:]) else: print(hex(ord(char))[2:] + " ", end="") ref_file_list.append(hex(ord(char))[2:]) return ref_file_list if __name__ == "__main__": dbg = MyDebug() connect_flag = dbg.connect() print("連接狀態: {}".format(connect_flag)) module_base = dbg.get_base_from_address(dbg.get_local_base()) print("模塊基地址: {}".format(hex(module_base))) # 得到內存機器碼 memory_hex_byte = get_memory_hex_ascii(module_base,0,100) # 得到磁盤機器碼 file_hex_byte = get_file_hex_ascii("d://Win32Project1.exe",0,100) # 輸出機器碼 print("\n內存機器碼: ",memory_hex_byte) print("\n磁盤機器碼: ",file_hex_byte) dbg.close()
讀取后輸出時會默認十六個字符一次換行,輸出效果如下。
我們繼續增加磁盤與內存對比過程,然后就能實現對特定內存區域與磁盤區域字節碼一致性的判斷。
#coding: utf-8 import binascii,os,sys from LyScript32 import MyDebug # 得到程序的內存鏡像中的機器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數據 char = dbg.read_memory_byte(address + index) count = count + 1 if count % 16 == 0: if (char) < 16: print("0" + hex((char))[2:]) ref_memory_list.append("0" + hex((char))[2:]) else: print(hex((char))[2:]) ref_memory_list.append(hex((char))[2:]) else: if (char) < 16: print("0" + hex((char))[2:] + " ",end="") ref_memory_list.append("0" + hex((char))[2:]) else: print(hex((char))[2:] + " ",end="") ref_memory_list.append(hex((char))[2:]) return ref_memory_list # 讀取程序中的磁盤鏡像中的機器碼 def get_file_hex_ascii(path,offset,len): count = 0 ref_file_list = [] with open(path, "rb") as fp: # file_size = os.path.getsize(path) fp.seek(offset) for item in range(offset,offset + len): char = fp.read(1) count = count + 1 if count % 16 == 0: if ord(char) < 16: print("0" + hex(ord(char))[2:]) ref_file_list.append("0" + hex(ord(char))[2:]) else: print(hex(ord(char))[2:]) ref_file_list.append(hex(ord(char))[2:]) else: if ord(char) < 16: print("0" + hex(ord(char))[2:] + " ", end="") ref_file_list.append("0" + hex(ord(char))[2:]) else: print(hex(ord(char))[2:] + " ", end="") ref_file_list.append(hex(ord(char))[2:]) return ref_file_list if __name__ == "__main__": dbg = MyDebug() connect_flag = dbg.connect() print("連接狀態: {}".format(connect_flag)) module_base = dbg.get_base_from_address(dbg.get_local_base()) print("模塊基地址: {}".format(hex(module_base))) # 得到內存機器碼 memory_hex_byte = get_memory_hex_ascii(module_base,0,1024) # 得到磁盤機器碼 file_hex_byte = get_file_hex_ascii("d://Win32Project1.exe",0,1024) # 輸出機器碼 for index in range(0,len(memory_hex_byte)): # 比較磁盤與內存是否存在差異 if memory_hex_byte[index] != file_hex_byte[index]: # 存在差異則輸出 print("\n相對位置: [{}] --> 磁盤字節: 0x{} --> 內存字節: 0x{}". format(index,memory_hex_byte[index],file_hex_byte[index])) dbg.close()
代碼運行后即可輸出,存在差異的相對位置:
內存ASCII碼解析
通過封裝的get_memory_hex_ascii
得到內存機器碼,然后再使用如下過程實現輸出該內存中的機器碼所對應的ASCII碼。
from LyScript32 import MyDebug import os,sys # 轉為ascii def to_ascii(h): list_s = [] for i in range(0, len(h), 2): list_s.append(chr(int(h[i:i+2], 16))) return ''.join(list_s) # 轉為16進制 def to_hex(s): list_h = [] for c in s: list_h.append(hex(ord(c))[2:]) return ''.join(list_h) # 得到程序的內存鏡像中的機器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數據 char = dbg.read_memory_byte(address + index) count = count + 1 if count % 16 == 0: if (char) < 16: ref_memory_list.append("0" + hex((char))[2:]) else: ref_memory_list.append(hex((char))[2:]) else: if (char) < 16: ref_memory_list.append("0" + hex((char))[2:]) else: ref_memory_list.append(hex((char))[2:]) return ref_memory_list if __name__ == "__main__": dbg = MyDebug() dbg.connect() eip = dbg.get_register("eip") # 得到模塊基地址 module_base = dbg.get_base_from_address(dbg.get_local_base()) # 得到指定區域內存機器碼 ref_memory_list = get_memory_hex_ascii(module_base,0,1024) # 解析ascii碼 break_count = 1 for index in ref_memory_list: if break_count %32 == 0: print(to_ascii(hex(int(index, 16))[2:])) else: print(to_ascii(hex(int(index, 16))[2:]),end="") break_count = break_count + 1 dbg.close()
輸出效果如下,如果換成中文,那就是一個中文搜索引擎了。
內存特征碼匹配
通過二次封裝get_memory_hex_ascii()
實現掃描內存特征碼功能,如果存在則返回True否則返回False。
from LyScript32 import MyDebug import os,sys # 得到程序的內存鏡像中的機器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數據 char = dbg.read_memory_byte(address + index) count = count + 1 if count % 16 == 0: if (char) < 16: ref_memory_list.append("0" + hex((char))[2:]) else: ref_memory_list.append(hex((char))[2:]) else: if (char) < 16: ref_memory_list.append("0" + hex((char))[2:]) else: ref_memory_list.append(hex((char))[2:]) return ref_memory_list # 在指定區域內搜索特定的機器碼,如果完全匹配則返回 def search_hex_ascii(address,offset,len,hex_array): # 得到指定區域內存機器碼 ref_memory_list = get_memory_hex_ascii(address,offset,len) array = [] # 循環輸出字節 for index in range(0,len + len(hex_array)): # 如果有則繼續裝 if len(hex_array) != len(array): array.append(ref_memory_list[offset + index]) else: for y in range(0,len(array)): if array[y] != ref_memory_list[offset + index + y]: return False array.clear() return False if __name__ == "__main__": dbg = MyDebug() dbg.connect() eip = dbg.get_register("eip") # 得到模塊基地址 module_base = dbg.get_base_from_address(dbg.get_local_base()) re = search_hex_ascii(module_base,0,100,hex_array=["0x4d","0x5a"]) dbg.close()
特征碼掃描一般不需要自己寫,自己寫的麻煩,而且不支持通配符,可以直接調用我們API中封裝好的scan_memory_one()
它可以支持??
通配符模糊匹配,且效率要高許多。
原文鏈接:https://www.cnblogs.com/LyShark/p/16547840.html
相關推薦
- 2022-08-13 windows上使用docker搭建kafka
- 2023-12-19 Mybatis使用注解實現復雜動態SQL
- 2024-03-09 【Redis】什么是緩存穿透,如何預防緩存穿透?
- 2024-01-14 springboot-mybatis/JPA流式查詢
- 2022-02-26 微信小程序 - 所有頁面一次性(只需要執行一次)全部開啟分享朋友圈功能(wx.showShareMe
- 2022-04-22 Element UI 使用表單校驗,正確輸入后,仍然有提示信息
- 2022-04-19 在html中src和href的區別,以及img中的srcset的作用是什么?
- 2023-05-15 Pandas處理DataFrame稀疏數據及維度不匹配數據分析詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支