LyScript實現(xiàn)內(nèi)存交換與差異對比的方法詳解
LyScript 針對內(nèi)存讀寫函數(shù)的封裝功能并不多,只提供了內(nèi)存讀取和內(nèi)存寫入函數(shù)的封裝,本篇文章將繼續(xù)對API進行封裝,實現(xiàn)一些在軟件逆向分析中非常實用的功能,例如內(nèi)存交換,內(nèi)存區(qū)域?qū)Ρ?,磁盤與內(nèi)存鏡像比較,特征碼檢索等功能。
LyScript項目地址:https://github.com/lyshark/LyScript
內(nèi)存區(qū)域交換
實現(xiàn)被加載程序內(nèi)特定一塊內(nèi)存區(qū)域的交換,該方法實現(xiàn)原理就是兩個變量之間的交換,只是在交換時需要逐個字節(jié)進行,調(diào)用read_memory_byte()函數(shù)實現(xiàn)起了很容易。
from LyScript32 import MyDebug
# 交換兩個內(nèi)存區(qū)域
def memory_xchage(dbg,memory_ptr_x,memory_ptr_y,bytes):
ref = False
for index in range(0,bytes):
# 讀取兩個內(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é)點交換后如下:

內(nèi)存區(qū)域?qū)Ρ?/h2>
可用于對比該進程內(nèi)存中的特定一塊區(qū)域的差異,返回是列表中的字典形式,分別傳入對比內(nèi)存x,y以及需要對比的內(nèi)存長度,此處建議不要超過1024字節(jié)。
from LyScript32 import MyDebug
# 對比兩個內(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}
# 讀取兩個內(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)存對比
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()
對比特定內(nèi)存區(qū)域,返回差異字節(jié)地址:

內(nèi)存與磁盤機器碼比較
通過調(diào)用read_memory_byte()函數(shù),或者open()打開文件,等就可以得到程序磁盤與內(nèi)存中特定位置的機器碼參數(shù),然后通過對每一個列表中的字節(jié)進行比較,就可得到特定位置下磁盤與內(nèi)存中的數(shù)據(jù)是否一致的判斷。
#coding: utf-8
import binascii,os,sys
from LyScript32 import MyDebug
# 得到程序的內(nèi)存鏡像中的機器碼
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
# 讀取程序中的磁盤鏡像中的機器碼
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)存機器碼
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內(nèi)存機器碼: ",memory_hex_byte)
print("\n磁盤機器碼: ",file_hex_byte)
dbg.close()
讀取后輸出時會默認(rèn)十六個字符一次換行,輸出效果如下。

我們繼續(xù)增加磁盤與內(nèi)存對比過程,然后就能實現(xiàn)對特定內(nèi)存區(qū)域與磁盤區(qū)域字節(jié)碼一致性的判斷。
#coding: utf-8
import binascii,os,sys
from LyScript32 import MyDebug
# 得到程序的內(nèi)存鏡像中的機器碼
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
# 讀取程序中的磁盤鏡像中的機器碼
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)存機器碼
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)):
# 比較磁盤與內(nèi)存是否存在差異
if memory_hex_byte[index] != file_hex_byte[index]:
# 存在差異則輸出
print("\n相對位置: [{}] --> 磁盤字節(jié): 0x{} --> 內(nèi)存字節(jié): 0x{}".
format(index,memory_hex_byte[index],file_hex_byte[index]))
dbg.close()
代碼運行后即可輸出,存在差異的相對位置:

內(nèi)存ASCII碼解析
通過封裝的get_memory_hex_ascii得到內(nèi)存機器碼,然后再使用如下過程實現(xiàn)輸出該內(nèi)存中的機器碼所對應(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進制
def to_hex(s):
list_h = []
for c in s:
list_h.append(hex(ord(c))[2:])
return ''.join(list_h)
# 得到程序的內(nèi)存鏡像中的機器碼
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)存機器碼
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()
輸出效果如下,如果換成中文,那就是一個中文搜索引擎了。

內(nèi)存特征碼匹配
通過二次封裝get_memory_hex_ascii()實現(xiàn)掃描內(nèi)存特征碼功能,如果存在則返回True否則返回False。
from LyScript32 import MyDebug
import os,sys
# 得到程序的內(nèi)存鏡像中的機器碼
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)搜索特定的機器碼,如果完全匹配則返回
def search_hex_ascii(address,offset,len,hex_array):
# 得到指定區(qū)域內(nèi)存機器碼
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()
特征碼掃描一般不需要自己寫,自己寫的麻煩,而且不支持通配符,可以直接調(diào)用我們API中封裝好的scan_memory_one()它可以支持??通配符模糊匹配,且效率要高許多。
到此這篇關(guān)于LyScript實現(xiàn)內(nèi)存交換與差異對比的方法詳解的文章就介紹到這了,更多相關(guān)LyScript內(nèi)存交換 對比內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pip install python 快速安裝模塊的教程圖解
這篇文章主要介紹了pip install python 如何快速安裝模塊,本文圖文并茂給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10
Transpose 數(shù)組行列轉(zhuǎn)置的限制方式
今天小編就為大家分享一篇Transpose 數(shù)組行列轉(zhuǎn)置的限制方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
Python 實現(xiàn)Windows開機運行某軟件的方法
今天小編就為大家分享一篇Python 實現(xiàn)Windows開機運行某軟件的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10
如何實現(xiàn)Django Rest framework版本控制
這篇文章主要介紹了如何實現(xiàn)Django Rest framework版本控制,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07

