暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

利用Keystone快速汇编并提取机器码

青衣十三楼飞花堂 2018-11-09
2687

ARM汇编写相对地址的bl,已知PC和目标地址,想写个.s,利用.org之类的指示符指定PC,然后"-c"编译,"objdump -d"查看机器码。不考虑ldr+blx。更进一步,想将几个固定地址的片段写在同一个.s里,比如代码、数据在不同地址。不考虑位置无关代码的自定位技巧。原始意图大致如此,但我用gcc未能得逞。

.org的第一形参是有符号整型,对于32-bits来说,0x80000000及以上的数被认为是负数,达不到预期目的。即使让它成为无符号整型或者动用64-bits,gcc/gas的.org指示符会实际填充,导致.o文件庞大。总之,原生.org不满足需求。

一度考虑用rasm2:

$ rasm2 -a arm -b 32 -o 0xf0e0dee0 -D "3a 06 00 eb"
0xf0e0dee0   4                 3a0600eb  bl 4041275344

$ rasm2 -a arm -b 32 -o 0xf0e0dee0 "bl 0xf0e0f7d0"
Branch into out of range
Cannot assemble 'bl 0xf0e0df70' at line 3
invalid

rasm2的反汇编正确,汇编失败,这可能与32-bits有关。nasm不支持arm。挣扎很久之后,bluerust推荐:

Keystone is a lightweight multi-platform, multi-architecture assembler framework
https://github.com/keystone-engine/keystone

源码可以在Linux、Windows下顺利编译,自带一个kstool用于演示。

$ ./kstool arm "bl 0xf0e0f7d0" 0xf0e0dee0
bl 0xf0e0f7d0 = [ 3a 06 00 eb ]

上例指定了bl指令所在地址,生成的机器码是相对跳转。动用分号后可以单行输入多
条指令:

$ echo -n "push {ip, lr};mov r0, #0xff000000" | ./kstool arm
push {ip, lr};mov r0, #0xff000000 = [ 00 50 2d e9 ff 04 a0 e3 ]

kstool在*nix下支持从stdin读入,Windows版不支持。从kstool.cpp看看,它曾经打算支持多行输入,但未能真正实现。

为了利用Keystone,很简单,大致这么几步:

ks_open()   指定CPU
ks_asm()    指定基址、汇编指令
printf()    输出机器码
ks_free()   释放动态分配的机器码空间
ks_close()  关闭

kstool_arm_sample.cpp如下:

(参txt原文)

(http://scz.617.cn:8/misc/201811071803.txt)


$ kstool_arm_sample <assembly> [base]

$ ./kstool_arm_sample "bl 0x8080df70" 0x8080dee0
000000008080dee0 [ 22 00 00 eb ] bl 0x8080df70

说个与ARM汇编无关与x64汇编相关的事。keystone汇编某条x64指令时(见后)生成的机器码与IDA显示不符,我以为是BUG,唆使bluerust跟作者联系一下,然后他较了一下真,有了后续内容。

就"mov rax, qword ptr gs:[188h]"而言,有两种编码方案:

mov rax, qword ptr gs:[dword 188h]  [ 65 48 8b 04 25 88 01 00 00 ]
mov rax, qword ptr gs:[qword 188h]  [ 65 48 a1 88 01 00 00 00 00 00 00 ]

此处的188h是displacement,IDA、gas对此做了优化,使用32-bits displacement,ks_asm()死活使用64-bits displacement。

$ ./kstool x64 "mov rax, qword ptr gs:[0x188]"
mov rax, qword ptr gs:[0x188] = [ 65 48 a1 88 01 00 00 00 00 00 00 ]

nasm语法可以对立即数指定位宽描述符:

BITS 64

    mov rax, [dword gs:0x188]
    mov rax, [qword gs:0x188]

$ nasm -f bin -o test.bin test.nasm
$ xxd -g 1 test.bin
00000000: 65 48 8b 04 25 88 01 00 00 65 48 a1 88 01 00 00  eH..%....eH.....
00000010: 00 00 00 00                                      ....
$ rasm2 -a x86 -b 64 -s intel -D 65488b0425880100006548a18801000000000000
0x00000000   9       65488b042588010000  mov rax, qword gs:[0x188]
0x00000009  11   6548a18801000000000000  movabs rax, qword gs:[0x188]

rasm2反汇编"mov rax, [qword gs:0x188]"时将mov显示成movabs,gas处理movabs时使用64-bits displacement。cdb则对两种情况都显示成mov,但为了强调64-bits,将立即数显示成"gs:[0000000000000188h]"。

> eb rip 65 48 8b 04 25 88 01 00 00 65 48 a1 88 01 00 00 00 00 00 00
> u rip l 2
00000000`ff662ff8 65488b042588010000 mov   rax,qword ptr gs:[188h]
00000000`ff663001 6548a18801000000000000 mov rax,qword ptr gs:[0000000000000188h]

上面两条指令效果完全一样,但机器码不同。

keystone支持nasm语法,但支持得不完整,比如不支持立即数位宽描述符:

$ ./kstool x64nasm "mov rax, qword gs:[0x188]"
= [ 65 48 a1 88 01 00 00 00 00 00 00 ]
$ ./kstool x64nasm "mov rax, qword gs:[dword 0x188]"
ERROR: failed on ks_asm()

文章转载自青衣十三楼飞花堂,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论