x64dbgpy插件使用与Python代码样例
2020-06-09 01:21:06 Author: bbs.pediy.com(查看原文) 阅读量:748 收藏


01前言

x64dbg工具的更新速度很活跃,经过几年使用人数已经很高了。刚上手觉得它很多和OD比较类似,不过它的在线文档确比较“专家化”,因此碰到一些问题也经常需要在github上向开发者提问了解。
作为动态调试工具,它本身也支持脚本功能,不过支持高级语言才是效率工具,它通过x64dbgpy插件支持python脚本;本文内不涉及python语法。

02安装

1, 插件仓库地址:https://github.com/x64dbg/x64dbgpy
2, 安装信息仓库Wiki说明也给的比较清楚,包含三部分:

  • x64dbg 插件文件:x64dbgpy.dp64, x64dbgpy.dp32文件
  • SDK : x64dbgpy 库文件,包含Python相关的API。
  • Python依赖和系统依赖。
    完成安装后,从x64dbg的菜单下就能看到插件了: "插件"->"x64dbgpy"

03脚本开发

作为样例,主要解析x64dbgpy的SDK内容和API使用。本例使用场景:对sourceinsight4进行自动化Patch生成。

03.1 SDK目录安装:

SDK主要需要被脚本引用,需要安装到:
1, x64dbg的plugins目录;
2, 方便IDE能进行语法提示,在自己创建的项目目录下或者Python的site-packages目录;

03.2 SDK的API能力:

SDK包含有源码,所以不会细讲每个API,从目录结果上就可以看到它的API定义和分类:
1,全局API调用入口:x64dbg.py的定义,通过它可以引用全部API内容。
2,对子模块的API也可以直接引用调用,子模块有:symbol, stack, register, pattern...等。
图片描述

03.3SDK的几个API说明:

从支持能力上,x64dbgpy应该在高级语言环境支持所有x64dbg的命令功能调用,事实也确实这样,一部分API被开发者显示的封闭成API,有一部分可扩展的API:
1, x64dbg.DbgValFromString(cmd) : 执行x64dbg命令集,并返回执行结果。如果看名称很容易被x64dbg.DbgEval给带偏了。
2, memory.Write():这个内存写操作的改变,x64dbg并不生成patch信息。
3, 可以再补充。

03.4整理场景功能编写:

从功能需要分为几部分:
1,定位需要patch的模块在内存中的位置。
相关API:

  • module.GetMainModuleName() : 获取主模块信息。
  • module.GetMainModuleSectionList() :获取主模块的分段信息。
    2,Patch特征查找和生成对应的Patch结果;
  • pattern.FindMem : 内存特征匹配,不使用pattern.SearchAndReplace是因为它不产生patch信息。
    3,生成Patch文件。
  • 比较容易,主要是根据patch点的信息,只在成x64dbg支持的patch文件。其中x64dbg中的patch模式为:rva: <raw byte data>-><patch byte data>
    具体代码如下:
from x64dbgpy.pluginsdk import *

#-*---------------------------------------------------------------------------------------------
#-*  VERIFY:
#-*  Tested under sourceinsight4 114, 115 version . 
#-@---------------------------------------------------------------------------------------------

class X64dbgLog(object):
    Dbg = [0, 'Debug']
    Warn = [1, 'Warn']
    Info = [2, 'Info']
    Err = [3, 'Error']
    Crital = [4, 'Critical']
    LogLevel = Info

    @staticmethod
    def logger(msg, level=Info):
        if level[0] >= X64dbgLog.LogLevel[0]:
            x64dbg.GuiAddLogMessage('### [%s] %s\n' % (level[1], msg))
        pass


def str_2_hex_pattern_str(str):
    return ' '.join([hex(ord(c))[-2:] for c in str])


class PEPatcher(object):
    def __init__(self, text_patchs, public_key=None):
        self.patch_patterns = text_patchs
        self.public_key = public_key
        self.module_file = module.GetMainModuleName()
        self.module_sections = module.GetMainModuleSectionList()
        self.patch_dict = {self.module_file: {}}
        for mod_it in self.module_sections:
            X64dbgLog.logger("sect %s,: (0x%X, 0x%X)" % (mod_it.name, mod_it.addr, mod_it.size))
            if mod_it.name == '.data':
                self.data_addr = mod_it.addr
                self.data_size = memory.GetSize(mod_it.addr, False, False)
            elif mod_it.name == '.text':
                self.text_addr = mod_it.addr
                self.text_size = memory.GetSize(mod_it.addr, False, False)
            pass

    def get_text_segment_patch(self):
        for pt_it in self.patch_patterns.keys():
            match_count = 0
            search_addr = self.text_addr
            search_size = self.text_size
            while True:
                find_ret = pattern.FindMem(search_addr, search_size, pt_it)
                if find_ret == 0:
                    if match_count == 0:
                        X64dbgLog.logger("Can't find pattern : %s \n" % pt_it, X64dbgLog.Err)
                        exit(-1)
                    else:
                        break  # the last point is get , stop search
                find_ret_rva = x64dbg.DbgValFromString(
                    'mod.rva(0x%X)' % (find_ret + self.patch_patterns[pt_it][0]))
                find_byte = memory.ReadByte(find_ret + self.patch_patterns[pt_it][0])
                self.patch_dict[self.module_file][find_ret_rva] = (
                    find_byte, self.patch_patterns[pt_it][1])
                X64dbgLog.logger(" ** Find pattern ( 0x%X #0x%X) 0x%02X -> 0x%02X :%s " %
                                 (find_ret, find_ret_rva, find_byte, self.patch_patterns[pt_it][1], pt_it))
                # support multi-points of patch .
                search_addr = find_ret + 1
                search_size = self.text_size - (search_addr - self.text_addr)
                match_count += 1
            pass

    def get_data_segment_patch(self):
        if self.public_key is None:
            return
        public_key_pattern = '-----BEGIN PUBLIC KEY-----'
        ret = pattern.FindMem(self.data_addr, self.data_size, str_2_hex_pattern_str(public_key_pattern))
        if ret == 0:
            X64dbgLog.logger("Can't find public key !!!")
            exit(0)
        X64dbgLog.logger("Find public key in : 0x%X !!!" % ret)
        patch_addr = ret + len(public_key_pattern)
        for char_it in self.public_key[len(public_key_pattern):]:
            tmp_byte = memory.ReadByte(patch_addr)
            if tmp_byte != ord(char_it):
                find_ret_rva = x64dbg.DbgValFromString('mod.rva(0x%X)' % patch_addr)
                self.patch_dict[self.module_file][find_ret_rva] = (tmp_byte, ord(char_it))
                X64dbgLog.logger("Patch  [0x%X #0x%X]: 0x%02X -> 0x%02X" %
                                 (patch_addr, find_ret_rva, tmp_byte, ord(char_it)), X64dbgLog.Dbg)
            patch_addr += 1
            pass

    def gen_x64dbg_patch_file(self, patch_file='./gen-patch.1337'):
        try:
            patch_file = open(patch_file, 'w')
            patch_file.write('>%s\n' % self.module_file)
            for patch_it in self.patch_dict[self.module_file].keys():
                patch_file.write('%08X:%X->%X\n' % (patch_it, self.patch_dict[self.module_file][patch_it][0],
                                                    self.patch_dict[self.module_file][patch_it][1]))
            patch_file.close()
        except IOError as e:
            X64dbgLog.logger(' Failed to write patch file : %s, Exit.' % patch_file, X64dbgLog.Err)
            exit(-1)


if __name__ == "__main__":
    patch_patterns = {
        "3D 70 17 00 00 ?? 75": [5, 0xEB],
        "?? C0 75 1D 8B 86 C4 0D": [0, 0x31],
        "?? C0 74 1E C7 84 24 28 04": [0, 0x31],
        "?? C0 74 47 8B CE E8 C7 E3 FF": [0, 0x31],
        # New patch point to bypass signature checking.
        "83 C4 0C ?? C8 00 00 00 0F 85": [3, 0xB8]
    }
    patch_pub_key = "-----BEGIN PUBLIC KEY-----\n" \
                    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoaA07NVkldoVZmPD8foI\n" \
                    "Q4ffxG9nMvmMiN2i0cd0+Rf6Uo2Z6JIuFseTFCoCwI62JseM247ckW5HHfeE1inE\n" \
                    "4Uqgq3oxdnxqImMrHeEzQ0u4UBXsVAacNl2ozwVfZqoTwkn+Uw096w1k/3Mj2PHJ\n" \
                    "PSHTP8D9QzuYn6X52po27Vzs82hpumiahiDxE48cxYcHJWuQpqmaCRpNrN+PyJtk\n" \
                    "vwqHa/zRB4/MwbtxltXlC/1ozbPuhNX91C3vw6mrcKaTVr8zNq4yy82prlwgksbA\n" \
                    "s7+AeF30mGbRM+mWf+FmwL1wmaEEa4QbjWdsnHz0xiPa/MbbgN6L6mrIJ3nQoqXK\n" \
                    "vQIDAQAB\n-----END PUBLIC KEY-----\n"    
    X64dbgLog.logger("** Strat to run python script : ")
    source_insight4_patcher = PEPatcher(patch_patterns)
    # source_insight4_patcher = PEPatcher(patch_patterns, patch_pub_key)
    source_insight4_patcher.get_text_segment_patch()
    source_insight4_patcher.get_data_segment_patch()
    source_insight4_patcher.gen_x64dbg_patch_file()
    # show hints
    X64dbgLog.logger("Patch file gen-patch.1337 is generated ! Please fix %s manually !!!" % source_insight4_patcher.module_file)
    gui.Message("Patch file gen-patch.1337 is generated ! Please fix %s manually !!!" % source_insight4_patcher.module_file)

03.5 脚本加载:

先通过x32dbg加载sourceinsigt4.exe:
图片描述
加载脚本&运行:
图片描述

[培训]科锐逆向工程师培训(6月24日远程教学开班, 第38期)!

最后于 12小时前 被nevinhappy编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-259970.htm
如有侵权请联系:admin#unsafe.sh