Ghidra 错误的函数参数和返回

逆向工程 吉德拉
2021-07-02 10:54:59

我是这里的新手,但我遇到了这个问题。

我正在尝试反编译一个函数,该函数又调用另一个函数(名为 charTranslateToHex)。

这是charTranslateToHex 汇编代码

                     *************************************************************
                     *                           FUNCTION                          
                     *************************************************************
                     undefined  __stdcall  charTranslateToHex (uint  param_1 , ui
     undefined         r0:1           <RETURN>
     uint              r0:4           param_1
     uint              r1:4           param_2
     undefined4        r2:4           param_3
     undefined2        Stack[-0xc]:2  local_c                                 XREF[2]:     000c1284 (W) , 
                                                                                           000c128c (W)   
                     charTranslateToHex                              XREF[3]:     Entry Point (*) , 
                                                                                  charTranslateToHex:0002a230 (T) , 
                                                                                  charTranslateToHex:0002a238 (c) , 
                                                                                  000f389c (*)   
000c1278 07  40  2d  e9    stmdb      sp!,{param_1  param_2  param_3  lr}
000c127c 00  10  a0  e3    mov        param_2 ,#0x0
000c1280 08  30  8d  e2    add        r3,sp,#0x8
000c1284 b4  10  cd  e1    strh       param_2 ,[sp,#local_c ]
000c1288 10  20  a0  e3    mov        param_3 ,#0x10
000c128c 04  00  63  e5    strb       param_1 ,[r3,#local_c ]!
000c1290 03  00  a0  e1    cpy        param_1 ,r3
000c1294 25  a6  fd  eb    bl         strtoul                                          ulong strtoul(char * __nptr, cha
000c1298 0e  80  bd  e8    ldmia      sp!,{param_2  param_3  r3 pc}

这就是 Ghidra 反编译它的方式:

void charTranslateToHex(uint param_1,uint param_2,undefined4 param_3)

{
  uint local_c;
  undefined4 uStack8;
  
  local_c = param_2 & 0xffff0000;
  local_c = local_c | param_1 & 0xff;
  uStack8 = param_3;
  strtoul((char *)&local_c,(char **)0x0,0x10);
  return;
}

现在回到主函数

......
                             LAB_000c1410                                    XREF[1]:     000c13c4 (j)   
        000c1410 00  00  6a  e0    rsb        param_1 ,r10 ,param_1
        000c1414 48  10  8d  e2    add        param_2 ,sp,#0x48
        000c1418 00  30  81  e0    add        param_4 ,param_2 ,param_1
        000c141c 08  00  8d  e5    str        param_1 ,[sp,#local_60 ]
        000c1420 1d  00  53  e5    ldrb       param_1 ,[r3,#local_3d ]
        000c1424 04  90  a0  e1    cpy        r9,r4
        000c1428 80  a3  fd  eb    bl         charTranslateToHex                               undefined charTranslateToHex(uin
        000c142c 24  31  9f  e5    ldr        param_4 ,[DAT_000c1558 ]                          = 0001529Dh
        000c1430 00  60  a0  e3    mov        r6,#0x0
        000c1434 10  00  8d  e5    str        param_1 ,[sp,#local_58 ]
        000c1438 03  30  8f  e0    add        param_4 ,pc,param_4
        000c143c 14  30  8d  e5    str        param_4 =>DAT_000d66dd ,[sp,#local_54 ]            = 25h    %
......

这是反编译版本:

iVar3 = sVar5 - uVar8;
uVar12 = charTranslateToHex((uint)local_3d[iVar3],(uint)&stack0xffffffe0,uVar10);
uVar9 = (uint)uVar12;
uVar11 = 0;
__s = param_4;

我不明白为什么 charTranslateToHex 需要三个参数以及为什么尽管主函数使用它的返回值它返回 void 。

你能帮我吗?

1个回答

理论

首先要理解的重要一点是,反编译器总是一次只反编译一个函数,并且默认情况下不会传播此分析的结果因此,反编译器会很乐意像分析的功能charTranslateToHex,并得出结论,它使用3个参数和返回无,但反编译一个函数来调用charTranslateToHex,例如main和结论是基于只有在代码maincharTranslateToHex需要3个参数,返回的东西。现在重要的一步是决定信任哪种解释并“承诺”它。

提交参数 ID

这可以通过Commit Parameter ID在反编译器列表的上下文菜单中手动完成,或者通过使用对所有函数执行此操作的分析通道来完成。

提交后有什么变化?

现在反编译器将假定charTranslateToHex具有您void charTranslateToHex(uint param_1,uint param_2,undefined4 param_3)提交的函数签名,例如,而不是尝试从main. 但在这种情况下,这实际上是错误的,会导致更糟的结果!

为什么会出错?

因为反编译器不知道对strtoulinside 的调用charTranslateToHex实际上返回了一些东西,所以它将作为charTranslateToHex. 这与您的问题是相同的问题,现在只是charTranslateToHex作为调用者和strtoul被调用者,而不是main作为调用者和charTranslateToHex没有可用于 的函数签名strtoul,因此不知道它是否返回某些内容。

您可以手动应用正确的签名,unsigned long int strtoul (const char* str, char** endptr, int base);也可以查找包含此库函数的适当 Ghidra 数据类型存档。然后反编译器将正确推断charTranslateToHex返回的内容并更改charTranslateToHex.