首页
社区
课程
招聘
[原创] x64dbgpy插件使用与Python代码样例
2020-6-7 10:37 11038

[原创] x64dbgpy插件使用与Python代码样例

2020-6-7 10:37
11038

x64dbgpy插件使用与代码样例


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:
图片描述
加载脚本&运行:
图片描述


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2020-6-8 11:49 被nevinhappy编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (12)
雪    币: 10545
活跃值: (3936)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jgs 2020-6-7 10:43
2
0
收藏,学习
雪    币: 31457
活跃值: (7099)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2020-6-28 15:37
3
0
@nevinhappy
试了很多次,按老外的视频做的,安不上,怀疑可能必须安vs2015
雪    币: 4089
活跃值: (8230)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
nevinhappy 2 2020-6-28 18:00
4
0
ninebell @nevinhappy 试了很多次,按老外的视频做的,安不上,怀疑可能必须安vs2015

应该是要装。我是参考https://github.com/x64dbg/x64dbgpy安装的。

雪    币: 31457
活跃值: (7099)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2020-6-28 18:23
5
0
nevinhappy 应该是要装。我是参考https://github.com/x64dbg/x64dbgpy安装的。
vs2015要上G,安装过程有个自定义貌似那个python的支持库,安装漫长,实在是受不了了,最后没再尝试。
好在有老外的脚本时边也是能做不少事的。
雪    币: 4089
活跃值: (8230)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
nevinhappy 2 2020-6-28 18:41
6
0
ninebell vs2015要上G,安装过程有个自定义貌似那个python的支持库,安装漫长,实在是受不了了,最后没再尝试。 好在有老外的脚本时边也是能做不少事的。

嗯,是的,那个变态玩艺,不过我装的时候,应该是已经装了VS2015,所以没碰到这个问题,因为有时候装一些别的PY库,也需要装这个鸟东西!

最后于 2020-6-28 18:43 被nevinhappy编辑 ,原因:
雪    币: 31457
活跃值: (7099)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2020-6-28 21:11
7
0
nevinhappy ninebell vs2015要上G,安装过程有个自定义貌似那个python的支持库,安装漫长,实在是受不了了,最后没再尝试。 好在有老外的脚本时边也是能做不少 ...

真是个让人又爱又恨的调试器
bug N多
兼容有问题,N多插件,不保证每个版本都通用。最后无奈,还是自己的土办法用Delphi编了个发送按键到调试器命令行的api下断工具。
哪方面不行,随时升级,还是自己说了算好。你StrongOD办到的事,咱的“土特产”也能办到。集各种小工具和破解总结于一身,不断进化与完善。

最后于 2020-6-28 21:13 被ninebell编辑 ,原因:
雪    币: 338
活跃值: (897)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
noword_forever 5 2020-6-28 21:34
8
0
只支持python2吗?
雪    币: 11805
活跃值: (4468)
能力值: ( LV5,RANK:77 )
在线值:
发帖
回帖
粉丝
qux 2020-8-15 11:13
9
0
试了一下,x64dbg.DbgScriptCmdExec(cmd) 执行命令的效果很好
雪    币: 31457
活跃值: (7099)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2020-12-9 13:21
10
0
@nevinhappy  
https://www.52pojie.cn/thread-1324859-1-1.html
请楼主,看看这个如何解决,今天用了近两个小时才把vs2015安装上,就差这个python's gui不出来了,以前是没事的,不知咋回事?  还有python for x36dbg调用的函数列表和实例的代码在哪里能看到更多?谢谢。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_jaajogiu 2021-6-10 14:36
11
0
你好 有偿求帮忙做个简单的x64dbg插件(我自用)  请问可以留个联系方式吗
雪    币: 31457
活跃值: (7099)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ninebell 2021-12-13 21:39
12
0
qux 试了一下,x64dbg.DbgScriptCmdExec(cmd) 执行命令的效果很好
确实不错,我也学会了。
雪    币: 269
活跃值: (5661)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zx_901106 2022-7-22 17:03
13
0

如果是单纯想要使用python实现调试,我推荐 LyScript项目,安装简单,无任何第三方依赖。

https://bbs.pediy.com/thread-273777.htm

最后于 2022-7-22 17:04 被zx_901106编辑 ,原因:
游客
登录 | 注册 方可回帖
返回