LyScript實(shí)現(xiàn)內(nèi)存交換與差異對(duì)比的方法詳解
LyScript 針對(duì)內(nèi)存讀寫(xiě)函數(shù)的封裝功能并不多,只提供了內(nèi)存讀取和內(nèi)存寫(xiě)入函數(shù)的封裝,本篇文章將繼續(xù)對(duì)API進(jìn)行封裝,實(shí)現(xiàn)一些在軟件逆向分析中非常實(shí)用的功能,例如內(nèi)存交換,內(nèi)存區(qū)域?qū)Ρ?,磁盤(pán)與內(nèi)存鏡像比較,特征碼檢索等功能。
LyScript項(xiàng)目地址:https://github.com/lyshark/LyScript
內(nèi)存區(qū)域交換
實(shí)現(xiàn)被加載程序內(nèi)特定一塊內(nèi)存區(qū)域的交換,該方法實(shí)現(xiàn)原理就是兩個(gè)變量之間的交換,只是在交換時(shí)需要逐個(gè)字節(jié)進(jìn)行,調(diào)用read_memory_byte()
函數(shù)實(shí)現(xiàn)起了很容易。
from LyScript32 import MyDebug # 交換兩個(gè)內(nèi)存區(qū)域 def memory_xchage(dbg,memory_ptr_x,memory_ptr_y,bytes): ref = False for index in range(0,bytes): # 讀取兩個(gè)內(nèi)存區(qū)域 read_byte_x = dbg.read_memory_byte(memory_ptr_x + index) read_byte_y = dbg.read_memory_byte(memory_ptr_y + index) # 交換內(nèi)存 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") # 內(nèi)存交換 flag = memory_xchage(dbg, 6815744,6815776,4) print("內(nèi)存交換狀態(tài): {}".format(flag)) dbg.close()
PE文件頭節(jié)點(diǎn)交換后如下:
內(nèi)存區(qū)域?qū)Ρ?/h2>
可用于對(duì)比該進(jìn)程內(nèi)存中的特定一塊區(qū)域的差異,返回是列表中的字典形式,分別傳入對(duì)比內(nèi)存x,y以及需要對(duì)比的內(nèi)存長(zhǎng)度,此處建議不要超過(guò)1024字節(jié)。
from LyScript32 import MyDebug # 對(duì)比兩個(gè)內(nèi)存區(qū)域 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} # 讀取兩個(gè)內(nèi)存區(qū)域 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") # 內(nèi)存對(duì)比 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()
對(duì)比特定內(nèi)存區(qū)域,返回差異字節(jié)地址:
內(nèi)存與磁盤(pán)機(jī)器碼比較
通過(guò)調(diào)用read_memory_byte()
函數(shù),或者open()
打開(kāi)文件,等就可以得到程序磁盤(pán)與內(nèi)存中特定位置的機(jī)器碼參數(shù),然后通過(guò)對(duì)每一個(gè)列表中的字節(jié)進(jìn)行比較,就可得到特定位置下磁盤(pán)與內(nèi)存中的數(shù)據(jù)是否一致的判斷。
#coding: utf-8 import binascii,os,sys from LyScript32 import MyDebug # 得到程序的內(nèi)存鏡像中的機(jī)器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數(shù)據(jù) 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 # 讀取程序中的磁盤(pán)鏡像中的機(jī)器碼 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("連接狀態(tài): {}".format(connect_flag)) module_base = dbg.get_base_from_address(dbg.get_local_base()) print("模塊基地址: {}".format(hex(module_base))) # 得到內(nèi)存機(jī)器碼 memory_hex_byte = get_memory_hex_ascii(module_base,0,100) # 得到磁盤(pán)機(jī)器碼 file_hex_byte = get_file_hex_ascii("d://Win32Project1.exe",0,100) # 輸出機(jī)器碼 print("\n內(nèi)存機(jī)器碼: ",memory_hex_byte) print("\n磁盤(pán)機(jī)器碼: ",file_hex_byte) dbg.close()
讀取后輸出時(shí)會(huì)默認(rèn)十六個(gè)字符一次換行,輸出效果如下。
我們繼續(xù)增加磁盤(pán)與內(nèi)存對(duì)比過(guò)程,然后就能實(shí)現(xiàn)對(duì)特定內(nèi)存區(qū)域與磁盤(pán)區(qū)域字節(jié)碼一致性的判斷。
#coding: utf-8 import binascii,os,sys from LyScript32 import MyDebug # 得到程序的內(nèi)存鏡像中的機(jī)器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數(shù)據(jù) 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 # 讀取程序中的磁盤(pán)鏡像中的機(jī)器碼 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("連接狀態(tài): {}".format(connect_flag)) module_base = dbg.get_base_from_address(dbg.get_local_base()) print("模塊基地址: {}".format(hex(module_base))) # 得到內(nèi)存機(jī)器碼 memory_hex_byte = get_memory_hex_ascii(module_base,0,1024) # 得到磁盤(pán)機(jī)器碼 file_hex_byte = get_file_hex_ascii("d://Win32Project1.exe",0,1024) # 輸出機(jī)器碼 for index in range(0,len(memory_hex_byte)): # 比較磁盤(pán)與內(nèi)存是否存在差異 if memory_hex_byte[index] != file_hex_byte[index]: # 存在差異則輸出 print("\n相對(duì)位置: [{}] --> 磁盤(pán)字節(jié): 0x{} --> 內(nèi)存字節(jié): 0x{}". format(index,memory_hex_byte[index],file_hex_byte[index])) dbg.close()
代碼運(yùn)行后即可輸出,存在差異的相對(duì)位置:
內(nèi)存ASCII碼解析
通過(guò)封裝的get_memory_hex_ascii
得到內(nèi)存機(jī)器碼,然后再使用如下過(guò)程實(shí)現(xiàn)輸出該內(nèi)存中的機(jī)器碼所對(duì)應(yīng)的ASCII碼。
from LyScript32 import MyDebug import os,sys # 轉(zhuǎn)為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) # 轉(zhuǎn)為16進(jìn)制 def to_hex(s): list_h = [] for c in s: list_h.append(hex(ord(c))[2:]) return ''.join(list_h) # 得到程序的內(nèi)存鏡像中的機(jī)器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數(shù)據(jù) 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()) # 得到指定區(qū)域內(nèi)存機(jī)器碼 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()
輸出效果如下,如果換成中文,那就是一個(gè)中文搜索引擎了。
內(nèi)存特征碼匹配
通過(guò)二次封裝get_memory_hex_ascii()
實(shí)現(xiàn)掃描內(nèi)存特征碼功能,如果存在則返回True否則返回False。
from LyScript32 import MyDebug import os,sys # 得到程序的內(nèi)存鏡像中的機(jī)器碼 def get_memory_hex_ascii(address,offset,len): count = 0 ref_memory_list = [] for index in range(offset,len): # 讀出數(shù)據(jù) 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 # 在指定區(qū)域內(nèi)搜索特定的機(jī)器碼,如果完全匹配則返回 def search_hex_ascii(address,offset,len,hex_array): # 得到指定區(qū)域內(nèi)存機(jī)器碼 ref_memory_list = get_memory_hex_ascii(address,offset,len) array = [] # 循環(huán)輸出字節(jié) for index in range(0,len + len(hex_array)): # 如果有則繼續(xù)裝 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()
特征碼掃描一般不需要自己寫(xiě),自己寫(xiě)的麻煩,而且不支持通配符,可以直接調(diào)用我們API中封裝好的scan_memory_one()
它可以支持??
通配符模糊匹配,且效率要高許多。
到此這篇關(guān)于LyScript實(shí)現(xiàn)內(nèi)存交換與差異對(duì)比的方法詳解的文章就介紹到這了,更多相關(guān)LyScript內(nèi)存交換 對(duì)比內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 實(shí)現(xiàn)鏈表實(shí)例代碼
這篇文章主要介紹了Python 實(shí)現(xiàn)鏈表實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04pip install python 快速安裝模塊的教程圖解
這篇文章主要介紹了pip install python 如何快速安裝模塊,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10Transpose 數(shù)組行列轉(zhuǎn)置的限制方式
今天小編就為大家分享一篇Transpose 數(shù)組行列轉(zhuǎn)置的限制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02Python 實(shí)現(xiàn)Windows開(kāi)機(jī)運(yùn)行某軟件的方法
今天小編就為大家分享一篇Python 實(shí)現(xiàn)Windows開(kāi)機(jī)運(yùn)行某軟件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10Django實(shí)現(xiàn)前臺(tái)上傳并顯示圖片功能
這篇文章主要介紹了Django實(shí)現(xiàn)前臺(tái)上傳并顯示圖片功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05如何實(shí)現(xiàn)Django Rest framework版本控制
這篇文章主要介紹了如何實(shí)現(xiàn)Django Rest framework版本控制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-075個(gè)很好的Python面試題問(wèn)題答案及分析
這篇文章主要介紹了5個(gè)很好的Python面試題問(wèn)題答案及分析,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01