radare在二进制文件提取方面的应用


启动与分析

(base) ➜  cwe_binary r2 d5db980dfc204a0f8df04dd1a2ec09fa

[0x08048760]> aaa

加载一个文件的命令为r2 文件名
分析的命令为aaa,这玩意有好几个等级,具体分析啥咱也忘了a越多分析的东西越多,最多是三个a。

使用python处理的话,json可以加载获取到的字符串

import r2pipe
r2 = r2pipe.open(filename, flags=['-2'])
r2.cmd('aaa')
json.loads(r2.cmd('aflj'))

函数和符号信息

afl
和
is

afl打印所有函数信息,is打印符号信息

如图加上j表示输出为json,~{}可以输出为这种可读的形式

[0x08048760]> aflj~{}
Do you want to print 4077 lines? (y/N) y
[
  {
    "offset": 134514528,
    "name": "entry0",
    "size": 33,
    "is-pure": "false",
    "realsz": 33,
    "noreturn": false,
    "stackframe": 28,
    "calltype": "cdecl",
    "cost": 15,
    "cc": 1,
    "bits": 32,
    "type": "fcn",
    "nbbs": 1,
    "edges": 0,
    "ebbs": 1,
    "signature": "entry0 ();",
    "minbound": 134514528,
    "maxbound": 134514561,
    "callrefs": [
      {
        "addr": 134514320,
        "type": "CALL",
        "at": 134514556
      }
    ],
    "datarefs": [
      134516736,
      134516640,
      134516548
    ],
    "indegree": 0,
    "outdegree": 1,
    "nlocals": 0,
    "nargs": 0,
    "bpvars": [

    ],
    "spvars": [

    ],
    "regvars": [

    ],
    "difftype": "new"
  },

offset为偏移量。

字段介绍:name

name为函数的名字

  • entry在ida里面是_start 是ida的入口地址

entry

  • main也是没有前缀的

  • "name": "sym.imp.puts",对应ida的plt表puts的地址

  • 无论是用户定义的函数还是调用的其他库函数都会有sym前缀,所以通过name区分用户自定义函数和系统函数是不行的

一些编译器生成的必要函数name可能跟ida的有一些不同

radare

radare的name

ida

ida的name

注意:调用的库函数在这里只会显示对应plt表项的信息。(通过imp前缀可以区分),通过去除掉一些编译器生成的函数可以得到所有的自定义的函数

其他字段

  • "size": 43 表示整个函数从开始到结束的大小。

注意 offset+size不是retn指令的地址,如图第一个箭头指向offset,第二个指向offset+size(或许是到下一个函数开始)

size

  • 对比了几个 "is-pure": "true"为ture的案例,都是不存在的函数,其中包含下标为imp标志的函数,loc标志的函数

  • size和realsz没什么区别。

  • "stackframe": 40 是函数整个栈帧的大小 合起来刚好是0x28(十进制40)

    栈帧

  • “bits”: 64, 应该是64位

  • “edges”: 4 表示cfg图边的数量

  • “signature”: “sym.tttt (int64_t arg1);”, 会包含函数和函数的参数,以及参数的数据类型。

  • “minbound”: 1706,为函数的开始 “maxbound”: 1786 为下一个函数的开始

  • “callrefs” 一个列表,包含在什么地方(at)调用(CALL)了哪个(addr)函数,在什么地方跳转(CODE)到什么地方。

"callrefs": [
      {
        "addr": 1408,
        "type": "CALL",
        "at": 1734
      },
      {
        "addr": 1752,
        "type": "CODE",
        "at": 1743
      },
  • “datarefs” 存放里面用到的一些数据的地址。

    "datarefs": [
        1956,
        1959
      ],
  • codexrefs

    "codexrefs": [
        {
          "addr": 1812,  这个函数的首地址
          "type": "CALL", 调用
          "at": 1706    某个函数在这个位置
        },
        {
          "addr": 1743, 本函数在什么地方跳转
          "type": "CODE",
          "at": 1752   跳转到
        },
        {
          "addr": 1750,
          "type": "CODE",
          "at": 1784
        }
      ],
    
    • “dataxrefs” 变量,参数,返回值,用到数据的信息,临时变量有一点不够准确
  "dataxrefs": [

    ],
    "indegree": 3,   引入多少数据(包含参数,用到的数据)
    "outdegree": 2,  返回的数量
    "nlocals": 2,    局部变量数量(不够准确)
    "nargs": 1,      参数数量
    "bpvars": [
      {
        "name": "var_14h",  14h表示距离ebp的偏移(实际上这是一个全局变量)
        "kind": "var",      变量
        "type": "int64_t",  
        "ref": {
          "base": "rbp",    基地址
          "offset": -20     偏移
        }
      },
      {
        "name": "var_4h",
        "kind": "var",
        "type": "uint32_t",
        "ref": {
          "base": "rbp",
          "offset": -4
        }
      }
    ],
  • “spvars” 参数的

    "spvars": [
    
      ],
      "regvars": [
        {
          "name": "arg1",
          "kind": "reg",
          "type": "int64_t",
          "ref": "rdi"
        }
      ],
    
## 获取符号信息

`isj~{}`
在不删除符号表的时候会展示很多东西,删除符号表(strip filename)之后就没有什么符号了,优点是分析速度很快

{
“name”: “crtstuff.c”,
“flagname”: “sym.crtstuff.c”,
“realname”: “crtstuff.c”,
“ordinal”: 35,
“bind”: “LOCAL”,
“size”: 0,
“type”: “FILE”,
“vaddr”: 0,
“paddr”: 0,
“is_imported”: false
},


## 跳转
跳转到分析的位置
`s addr`

## 查看汇编代码
先用s跳转到一个函数的开始

- `agf`查看cfg图

![cfg](https://raw.githubusercontent.com/tower111/picture/main/小书匠/1615697326304.png)

- `pdf` 查看汇编指令,调用关系。

![调用关系](https://raw.githubusercontent.com/tower111/picture/main/小书匠/1615697391784.png)

- `agfj~{}`展示每个块详细信息,方便获取一些字段

```bash
[
  {
    "name": "sym.tttt",
    "offset": 1674, 地址
    "ninstr": 31,   
    "nargs": 3,    参数数量
    "nlocals": 4,  局部变量数(汇编里面存放过都会计数,有些源代码没定义,只是编译器生成的临时存放数据的)
    "size": 102,   函数大小
    "stack": 40,  栈帧大小
    "type": "sym",
    "blocks": [    每个块的信息
      {
        "offset": 1674,   
        "size": 51,   
        "jump": 1732,  见后面的分析(如果跳转)
        "fail": 1725,  如果不跳转
        "trace": {     待补充
          "count": 55,
          "times": 1
        },
        "colorize": 0,
        "ops": [
          {
           "offset": 1674,
            "esil": "rbp,8,rsp,-,=[8],8,rsp,-=", 中间语言 见后面的分析
            "refptr": false,
            "fcn_addr": 1674,
            "fcn_last": 1811,
            "size": 1,
            "opcode": "push rbp",  
            "disasm": "push rbp", 汇编指令
            "bytes": "55",        字节码
            "family": "cpu",
            "type": "rpush",
            "reloc": false,
            "type_num": 268435468,
            "type2_num": 0,
            "flags": [
              "sym.tttt"
            ],
            "xrefs": [
              {
                "addr": 1858,
                "type": "CALL"
              }
            ]
          },

跳转

如下指令,在jnz跳转的时候会跳转到"jump": 1732 不跳的时候(汇编代码紧邻的)是"fail": 1725

cmp     [rbp+var_4], 1
jnz     short loc_6C4

中间语言

"esil": "rbp,8,rsp,-,=[8],8,rsp,-="
esil:Evaluable Strings Intermediate Language 可计算字符串中间语言。

目的是能够表示CPU执行的大多数常见操作,例如二进制算术运算,内存加载和存储,处理系统调用。这样,如果我们可以将指令转换为ESIL,就可以看到程序在运行时的功能,即使对于大多数隐秘的体系结构,您也绝对没有要调试的设备。

指令详细信息

s addr 跳转到一个块的开始(块地址的列表可以从agf获取到)

aoj 指令数 可以通过len(block['ops'])来确定

[0x0000068a]> aoj 2~{}
[
  {
    "opcode": "push rbp",
    "disasm": "push rbp",
    "pseudo": "push rbp",
    "description": "push word, doubleword or quadword onto the stack",
    "mnemonic": "push",    助记符
    "mask": "ff",
    "esil": "rbp,8,rsp,-,=[8],8,rsp,-=",
    "sign": false,
    "prefix": 0,
    "id": 588,
    "opex": {
      "operands": [
        {
          "size": 8,
          "rw": 1,
          "type": "reg",  分为imm(调用函数也在这),reg,mem
          "value": "rbp"  立即数为数值,寄存器为寄存器名
        }
      ]
    },
    "addr": 1674,
    "bytes": "55",
    "size": 1,
    "type": "rpush",
    "scale": 0,
    "refptr": 0,
    "cycles": 1,
    "failcycles": 0,
    "delay": 0,
    "stack": "inc",
    "stackptr": 8,
    "family": "cpu"
  },

一个稍微复杂的指令opex更多一点

"opcode": "lea rdi, [rip + 0x110]",
"disasm": "lea rdi, str.dddd",   disasm相比opcode会多一些分析,可读性更好

    "opex": {
      "operands": [
        {
          "size": 8,
          "rw": 2,
          "type": "reg",
          "value": "rdi"
        },
        {
          "size": 8,
          "rw": 1,
          "type": "mem",
          "base": "rip",   详细展开指令
          "scale": 1,
          "disp": 272     真实地址=[base*scale+disp] base为基地址寄存器,scale为规模,disp为偏移量(十进制) (如果是rax+rbx+0x10会变为rax*2+16)  如果是负数里面存放补码
        }
      ],
      "rex": true,
      "modrm": true,
      "disp": 272
    },

base为0的情况有

  • 'lea rdx, [rax*4]'(处理第二个操作数)
  • 'mov rax, qword fs:[0x28]'(段加偏移)

    字符串处理

    对字符串的处理
    "disasm": "lea rdi, str.dddd", 会在这里添加str. 也有可能没有被识别,被识别为了imm类型,可以判断改地址是否在字符串列表地址中,获取字符串列表的方式如下

izzj~{}指令可以获得指令的信息

{
    "vaddr": 481,    如果不是.strtab段两个地址是相等的,指向函数的地址
    "paddr": 6201,
    "ordinal": 56,
    "size": 26,      空间大小
    "length": 25,    长度
    "section": ".strtab",  strtab段在ida里是不显示的
    "type": "ascii",
    "string": "_ITM_registerTMCloneTable"
  },

函数调用指令

列出三种架构用到的函数调用

 x86_mnemonics = ['call', 'int']#包含函数调用和syscall
        arm_mnemonics = ['bl', 'blx']
        mips_mnemonics = ['jal', 'jalr', 'syscall']

转移指令的确定

列出了三种架构的转移指令

x86_mnemonics = ['BNDLDX', 'BNDMK', 'BNDMOV', 'BNDSTX'
            , 'CMOVA', 'CMOVZ', 'CMOVPO', 'CMOVPE', 'CMOVP', 'CMOVO', 'CMOVNZ', 'CMOVNP', 'CMOVNO', 'CMOVNG', 'CMOVL'
            , 'FIST', 'FISTP', 'FISTTP', 'FSAVE', 'KMOVB', 'KMOVD', 'KMOVQ', 'KMOVW'
            , 'LDDQU', 'LDS', 'LEA', 'LODS', 'LODSB', 'LODSD', 'LODSQ', 'LODSW'
            , 'LSS', 'LSL', 'MOV', 'MOVAPD', 'MOVAPS', 'MOVBE', 'MOVD', 'MOVDDUP', 'MOVDQ2Q', 'MOVDQA', 'MOVDQU'
            , 'MOVHLPS', 'MOVHPD', 'MOVHPS', 'MOVLHPS', 'MOVLPD', 'MOVLPS', 'MOVQ', 'MOVS', 'MOVSB', 'MOVSD', 'MOVNTQ'
            , 'MOVNTDQ', 'MOVMSKPS', 'MOVSQ', 'MOVSS', 'MOVSW', 'MOVSX', 'MOVSXD', 'MOVUPD', 'MOVUPS', 'MOVZX',
                         'PMOVMSKB'
            , 'PMOVSX', 'PMOVZX', 'PUSH', 'PUSHA', 'PUSHAD', 'PUSHF', 'STOS', 'STOSB', 'STOSD', 'STOSQ', 'STOSW'
            , 'VBROADCAST', 'VEXPANDPD', 'VEXPANDPS', 'VMOVDQA32', 'VMOVDQA64', 'VMOVDQU16', 'VMOVDQU32', 'VMOVDQU64',
                         'VMOVDQU8'
            , 'VPBROADCAST', 'VPBROADCASTB', 'VPEXPANDD', 'VPEXPANDQ', 'movb', 'movq']
        arm_mnemonics = ['MOV', 'MVN', 'MOVT', 'MRA', 'MAR', 'LDR', 'STR', 'PLD', 'PLI', 'PLDW', 'LDM', 'LDREX',
                         'LDREXD', 'STM', 'STREX', 'STREXD']
        mips_mnemonics = ['LB', 'LBE', 'LBU', 'LBUE', 'LD', 'LDE', 'LDU', 'LDUE', 'LDC1', 'LDC2'
            , 'LDL', 'LDPC', 'LDR', 'LDXC1', 'LH', 'LHE', 'LHU', 'LHUE', 'LL'
            , 'LLD', 'LLE', 'LLDP', 'LLWP', 'LLWPE', 'LSA', 'LUXC1', 'LW'
            , 'LWC1', 'LWC2', 'LWL', 'LWLE', 'LWPC'
            , 'LWR', 'LWRE', 'LWU', 'MOV', 'SB', 'SBE', 'SC'
            , 'SCD', 'SCDP', 'SCE', 'SCWP', 'SCWPE'
            , 'SD', 'SDBBP', 'SDC1', 'SDC2', 'SDL', 'SDR', 'SDXC1', 'SH', 'SHU', 'SHE'
            , 'SW', 'SWE', 'SWC1', 'SWC2', 'SWL', 'SWR', 'SWLE', 'SWRE', 'SWXC1']

算数指令

列出了三种架构的算数指令

x86_mnemonics = ['add', 'sub', 'div', 'imul', 'idiv', 'mul', 'shl', 'dec', 'adc', 'adcx', 'addpd', 'addps',
                         'addsd', 'addss', 'addsubpd', 'ADDSUBPS', 'adox', 'divpd', 'divps'
            , 'divsd', 'divss', 'dppd', 'dpps', 'f2xm1', 'fabs', 'fadd', 'faddp', 'fcos', 'fdiv', 'fdivp', 'fiadd',
                         'fidiv', 'fimul', 'fisub', 'fisubr', 'fmul', 'fmulp', 'FPATAN', 'FPREM', 'FPREM1', 'FPTAN',
                         'FRNDINT', 'FSCALE'
            , 'FSIN', 'FSINCOS', 'FSQRT', 'FSUB', 'FSUBP', 'FSUBR', 'FSUBRP', 'FYL2X', 'FYL2XP1', 'HADDPD', 'HADDPS',
                         'HSUBPD', 'HSUBPS', 'KADDB', 'KADDD', 'KADDD', 'KADDW', 'KSHIFTLB', 'KSHIFTLD', 'KSHIFTLQ',
                         'KSHIFTLW', 'KSHIFTRB', 'KSHIFTRD', 'KSHIFTRQ', 'KSHIFTRW'
            , 'MAXPD', 'MAXPS', 'MAXSD', 'MAXSS', 'MINPD', 'MINPS', 'MINSD', 'MINSS', 'MULPD'
            , 'MULPS', 'MULSS', 'MULSD', 'MULX', 'PADDB', 'PADDD', 'PADDQ', 'PADDSB', 'PADDSW', 'PADDUSB', 'PADDUSW'
            , 'PADDW', 'PAVGB', 'PAVGW', 'PHADDD', 'PHADDSW', 'PHADDW', 'PHMINPOSUW', 'PHSUBD', 'PHSUBSW', 'PHSUBW'
            , 'PMADDUBSW', 'PMADDWD', 'PMAXSB', 'PMAXSD', 'PMAXSQ', 'PMAXSW', 'PMAXUB', 'PMAXUD', 'PMAXUQ', 'PMAXUW',
                         'PMINSB'
            , 'PMINSD', 'PMINSQ', 'PMINSW', 'PMINUB', 'PMINUD', 'PMINUQ', 'PMINUW', 'PMULDQ', 'PMULHRSW', 'PMULHUW',
                         'PMULHW', 'PMULLD', 'PMULLQ'
            , 'PMULLW', 'PMULUDQ', 'PSADBW', 'PSLLD', 'PSLLW', 'PSRAD', 'PSLLQ', 'PSRAQ', 'PSRLQ', 'PSRLW'
            , 'PSUBB', 'PSUBD', 'PSUBQ', 'PSUBSB', 'PSUBSW', 'PSUBUSB', 'PSUBUSW', 'RCL', 'RCR'
            , 'ROL', 'ROR', 'ROUNDPD', 'ROUNDPS', 'ROUNDSD', 'ROUNDSS', 'RSQRTPS'
            , 'RSQRTSS', 'SAL', 'SAR', 'SARX', 'SBB', 'inc', 'SHLD', 'SHLX', 'SHR', 'SHRD', 'SHRX', 'SQRTPD', 'SQRTPS',
                         'SQRTSD', 'SQRTSS'
            , 'SUBPD', 'SUBPS', 'SUBSD', 'SUBSS', 'VFMADD132PD', 'VPSLLVD', 'VPSLLVQ', 'VPSLLVW', 'VPSRAVD', 'VPSRAVQ'
            , 'VPSRAVW', 'VPSRLVD', 'VPSRLVQ', 'VPSRLVW', 'VRNDSCALEPD', 'VRNDSCALEPS', 'XADD']

        arm_mnemonics = ['add', 'adc', 'qadd', 'dadd', 'sub', 'SBC', 'RSB', 'RSC', 'subs', 'qsub',
                         'add16', 'SUB16', 'add8', 'sub8', 'ASX', 'sax', 'usad8', 'SSAT', 'MUL'
            , 'smul', 'MLA', 'MLs', 'UMULL', 'UMLAL', 'UMaAL', 'SMULL', 'smlal'
            , 'SMULxy', 'SMULWy', 'SMLAxy', 'SMLAWy', 'SMLALxy', 'SMUAD'
            , 'SMLAD', 'SMLALD', 'SMUSD', 'SMLSD', 'SMLSLD', 'SMMUL'
            , 'SMMLA', 'MIA', 'MIAPH', 'MIAxy', 'SDIV', 'udiv'
            , 'ASR', 'LSL', 'LSR', 'ROR', 'RRX']

        mips_mnemonics = ['add', 'addu', 'addi', 'addiu', 'mult', 'multu', 'div', 'divu'
            , 'AUI', 'DAUI', 'DAHI', 'DATI', 'CLO', 'CLZ', 'DADD', 'DADDI'
            , 'DADDIU', 'DADDU', 'DCLO', 'DCLZ', 'DDIV', 'DDIVU', 'MOD'
            , 'MODU', 'DMOD', 'DMODU', 'DMULTU', 'DROTR', 'DROTR32', 'DSLLV'
            , 'DSRA', 'DSRA32', 'DSRAV', 'DSRL', 'DSRL32'
            , 'DSRLV', 'DSUB', 'DSUBU', 'DSRL', 'FLOOR', 'MAX', 'MIN', 'MINA', 'MAXA'
            , 'MSUB', 'MSUBU', 'MUL', 'MUH', 'MULU', 'MUHU', 'DMUL', 'DMUH'
            , 'DMULU', 'DMUHU', 'DMUL', 'NEG'
            , 'NMADD', 'NMSUB', 'RECIP', 'RINT', 'ROTR', 'ROUND', 'RSQRT'
            , 'SLL', 'SLLV', 'SQRT', 'SRA', 'SRAV', 'SRL', 'SRLV'
            , 'SUB', 'SUBU', 'madd', 'maddu', 'msub', 'msubu', 'sll'
            , 'srl', 'sra', 'sllv', 'srla', 'srlv']

评论
 上一篇
radare在二进制文件提取方面的应用 radare在二进制文件提取方面的应用
启动与分析(base) ➜ cwe_binary r2 d5db980dfc204a0f8df04dd1a2ec09fa [0x08048760]> aaa 加载一个文件的命令为r2 文件名分析的命令为aaa,这玩意有好几个等级,具体
2021-03-13
下一篇 
金盾pwn3 金盾pwn3
对输入数据进行了拼接然后输出,输出的时候有格式化字符串漏洞。循环限制输入三次。 第一次泄露elf文件基地址,第二次修改三次限制。之后泄露libc基地址,栈地址,修改返回地址输入exit返回。 #coding=utf-8 from pwn
2020-12-20
  目录