V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
v2410117
V2EX  ›  Python

请教如何使用 Python 直接对二进制文件进行修改

  •  
  •   v2410117 · 2020-10-29 09:08:16 +08:00 · 4182 次点击
    这是一个创建于 1488 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚接触 python 不久,想用 python 直接修改二进制文件中的某段字符串内容,在网上查询使用fopen然后用seek定位,write写入.我测试过确实能达到效果。

    但是如果替换的长度不一样,比如本来的字符串为test,我用上面的方法想替换成mytest,因为长度比原来的长,就替换不成功,本来我想的是,在内存里找一块空的地址,写入mytest,然后将地址替换到test里面,虽然想的很美好,但是实在不会操作,特来请教一下这种替换长度不一致的,该如何操作,提前致谢

    22 条回复    2020-10-29 23:11:51 +08:00
    whileFalse
        1
    whileFalse  
       2020-10-29 09:12:02 +08:00
    如果文件不大的话,全部读出-内存替换-全部写回
    fasionchan
        2
    fasionchan  
       2020-10-29 09:12:20 +08:00
    文件不大的话可以将整个文件读到内存,在内存中做替换后,再整体覆盖写入
    whileFalse
        3
    whileFalse  
       2020-10-29 09:17:56 +08:00
    replace_data = b'mytest'
    replace_begin = 3
    replace_end = 7

    with open('a.txt', 'rb') as f:
    data = f.read()
    print(data)
    print(data[replace_begin:replace_end])
    data = data[:replace_begin] + replace_data + data[replace_end:]
    print(data)
    with open('b.txt', 'wb') as f:
    f.write(data)
    no1xsyzy
        4
    no1xsyzy  
       2020-10-29 09:34:50 +08:00
    Python 不需要找 “空的地址”,你直接创建对象就会自动分配内存。
    f.read() 就会创建 bytes 对象,之后 replace 替换,完了再 f.write() 回去就成
    不一样长度的话,除非整 block,并且修改文件系统 metadata,不然从你修改的位置开始后面全部得覆写一遍的。
    lllllliu
        5
    lllllliu  
       2020-10-29 09:41:04 +08:00
    难道不是计算修改后的文件长度,修改区段表或者结构段定义头的长度,然后在修改或填充么。。
    zone10
        6
    zone10  
       2020-10-29 09:56:54 +08:00   ❤️ 1
    新手多找成型的代码看, 按照规范来写代码, 别老是以自己狭隘的思路写, 看多了你就知道有些问题压根不存在
    v2410117
        7
    v2410117  
    OP
       2020-10-29 10:09:41 +08:00
    @whileFalse 大佬您好,首先感谢您提供的代码,我使用测试后,发现修改后提示`segmentation fault`,无法运行,是还需要修改其他的结构吗?谢谢
    v2410117
        8
    v2410117  
    OP
       2020-10-29 10:10:57 +08:00
    @zone10 感谢您提供的建议,多多看代码!
    whileFalse
        9
    whileFalse  
       2020-10-29 10:14:32 +08:00
    @v2410117 你在代码相同目录下放一个 a.txt 文件,内容是“123test123”试试看
    playniuniu
        10
    playniuniu  
       2020-10-29 10:19:16 +08:00
    二进制文件比如 ELF 类型的是有特定格式的,你要是在中间随便增加长度,估计整个程序都运行不了。要增加长度,先确定二进制文件的类型,比如 ELF 格式的,是需要找一片空白区域,把新数据放进去,在把原来读这端程序的地方改成读新的,还是蛮麻烦的。
    v2410117
        11
    v2410117  
    OP
       2020-10-29 10:35:46 +08:00
    @whileFalse 文本文件是可以,但是二进制执行文件就不行了,应该是如楼上说的那样,还要修改结构啥的吧!
    v2410117
        12
    v2410117  
    OP
       2020-10-29 10:37:21 +08:00
    @playniuniu 嗯,对,确实如您所说的为 elf 格式,按直接拼接 bytes 的做法确实导致整个程序都无法运行了.我也是想的您后面提到的那个操作,先找个空白区域写好,然后修改读的地址,但是不太会用 python 操作,正在寻找解决办法中
    mumbler
        13
    mumbler  
       2020-10-29 10:40:57 +08:00 via Android
    二进制结构一般会固定字段长度,如果 test 没占满,后面一定会有空字节,就把 mytest 写入前 6 位。归根结底,要了解这种二进制的文件结构
    whileFalse
        14
    whileFalse  
       2020-10-29 10:43:43 +08:00
    @v2410117 可执行文件有文件格式啊……你得研究文件格式。修改还是按照我说的方法修改的。但在特定的文件格式下应该怎么修改,那你得自己研究。
    zhyl
        15
    zhyl  
       2020-10-29 10:46:58 +08:00
    如果需要写入后的二进制文件还是正常运行,那么重点不在于如何写入,需要了解对应二进制文件的格式,例如 windows 下 PE 格式以区段划分,代码存放在代码段,数据存放在数据段,如果修改(变长或减短)数据段的内容,那么在代码段中所有这块修改数据之后的数据被引用时,其引用的地址都需要修正。
    belite
        16
    belite  
       2020-10-29 10:54:13 +08:00 via iPhone
    我有一个想法 边读边改边写 写到另一个空文件里 完成后替换原文件
    aneostart173
        17
    aneostart173  
       2020-10-29 10:55:27 +08:00
    你这个要求对应文本编辑器的插入编辑操作,文本编辑器的实现就很复杂,一两句说不清楚。
    CRVV
        18
    CRVV  
       2020-10-29 11:07:42 +08:00
    @v2410117

    如果你连改文件内容都需要来发帖子问,改 ELF 然后还要能跑属于你不可能完成的事情,放弃吧。

    https://blog.0patch.com/2017/11/did-microsoft-just-manually-patch-their.html
    这是微软做过然后能上新闻的操作。
    playniuniu
        19
    playniuniu  
       2020-10-29 14:55:21 +08:00
    @v2410117 这篇文章有关于 Android so 文件 的修改方法 http://www.520monkey.com/archives/561,你可以参考一下,其他 ELF 格式应该差不多
    imn1
        20
    imn1  
       2020-10-29 15:05:54 +08:00
    1.字节是可以使用 replace 函数的
    2.可以前后截取,再用新字节重新拼接

    如果二进制文件是某种格式,自然要按那种格式的规范来做,不是这样随意改动,例如 jpg 里面改动 exif,exif 实际只是字节数据,可以改动不影响图像显示,但也是要符合 exif 以及 jpeg 规范的,没有足够知识的话,最好用相关模块辅助完成
    xcai007
        21
    xcai007  
       2020-10-29 18:05:02 +08:00
    用 mmap

    import mmap
    with open('file', 'rb) as f:
    with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as contents:
    start = contents.find('test')
    print(contents[:start]+'mytest'+contents[start+len('test'):]
    Owenjia
        22
    Owenjia  
       2020-10-29 23:11:51 +08:00
    修改 elf 文件的话可以看下 lief 这个库?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3241 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 13:12 · PVG 21:12 · LAX 05:12 · JFK 08:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.