如何简化将自身作为参数引用的函数? 这是什么意思

如何解决如何简化将自身作为参数引用的函数? 这是什么意思

我经常遇到一个调用自身的函数(在伪代码中,由 IDA 生成)例如:

result = (**(__int64 (__fastcall ***)(volatile signed __int32 *))lambda)(lambda);
  1. 既然反汇编是call qword ptr [rax],那我把c中的伪代码翻译成result = lambda();不就可以了吗?
  2. 为什么在伪代码中函数将自身作为参数?
  3. 当有诸如 lambda + 8i64(即 call qword ptr [rax+8])之类的调用时会发生什么?

这里有一个更完整的上下文:

__int64 __fastcall CR_maybeParseWithLambda(_QWORD *a1,__int64 newPtr,__int64 positionOrCounter)
{
  volatile signed __int32 *lambda; // rdi
  __int64 result; // rax

  lambda = (volatile signed __int32 *)a1[1];
  if ( lambda )
  {
    result = (unsigned int)_InterlockedExchangeAdd(lambda + 2,0xFFFFFFFF);
    if ( (_DWORD)result == 1 )
    {
      result = (**(__int64 (__fastcall ***)(volatile signed __int32 *))lambda)(lambda);
      if ( _InterlockedExchangeAdd(lambda + 3,0xFFFFFFFF) == 1 )
        result = (*(__int64 (__fastcall **)(volatile signed __int32 *))(*(_QWORD *)lambda + 8i64))(lambda);
      a1[1] = positionOrCounter;
      *a1 = newPtr;
    }
    else
    {
      a1[1] = positionOrCounter;
      *a1 = newPtr;
    }
  }
  else
  {
    a1[1] = positionOrCounter;
    *a1 = newPtr;
  }
  return result;
}

反汇编,同样来自 IDA:

.text:0000000180005F70 ; __int64 __fastcall CR_maybeParseWithLambda(_QWORD *a1,__int64 positionOrCounter)
.text:0000000180005F70 CR_maybeParseWithLambda proc near       ; CODE XREF: sub_180005B10+10F↑p
.text:0000000180005F70                                         ; sub_180005B10+14A↑p ...
.text:0000000180005F70
.text:0000000180005F70 arg_0           = qword ptr  8
.text:0000000180005F70 arg_8           = qword ptr  10h
.text:0000000180005F70 arg_10          = qword ptr  18h
.text:0000000180005F70 arg_18          = qword ptr  20h
.text:0000000180005F70
.text:0000000180005F70                 mov     [rsp+arg_8],rbx
.text:0000000180005F75                 mov     [rsp+arg_10],rbp
.text:0000000180005F7A                 mov     [rsp+arg_18],rsi
.text:0000000180005F7F                 push    rdi
.text:0000000180005F80                 sub     rsp,20h
.text:0000000180005F84                 mov     rdi,[rcx+8]
.text:0000000180005F88                 mov     rsi,r8
.text:0000000180005F8B                 mov     rbp,rdx
.text:0000000180005F8E                 mov     rbx,rcx
.text:0000000180005F91                 test    rdi,rdi
.text:0000000180005F94                 jz      short loc_180005FF3
.text:0000000180005F96
.text:0000000180005F96 loc_180005F96:                          ; DATA XREF: .rdata:0000000180401E74↓o
.text:0000000180005F96                                         ; .rdata:0000000180401E84↓o ...
.text:0000000180005F96                 mov     [rsp+28h+arg_0],r14
.text:0000000180005F9B                 or      r14d,0FFFFFFFFh
.text:0000000180005F9F                 mov     eax,r14d
.text:0000000180005FA2                 lock xadd [rdi+8],eax
.text:0000000180005FA7                 cmp     eax,1
.text:0000000180005FAA                 jnz     short loc_180005FEA
.text:0000000180005FAC                 mov     rax,[rdi]
.text:0000000180005FAF                 mov     rcx,rdi
.text:0000000180005FB2                 call    qword ptr [rax]
.text:0000000180005FB4                 lock xadd [rdi+0Ch],r14d
.text:0000000180005FBA                 cmp     r14d,1
.text:0000000180005FBE                 jnz     short loc_180005FC9
.text:0000000180005FC0                 mov     rax,[rdi]
.text:0000000180005FC3                 mov     rcx,rdi
.text:0000000180005FC6                 call    qword ptr [rax+8]
.text:0000000180005FC9
.text:0000000180005FC9 loc_180005FC9:                          ; CODE XREF: CR_maybeParseWithLambda+4E↑j
.text:0000000180005FC9                 mov     [rbx+8],rsi
.text:0000000180005FCD                 mov     [rbx],rbp
.text:0000000180005FD0
.text:0000000180005FD0 loc_180005FD0:                          ; CODE XREF: CR_maybeParseWithLambda+81↓j
.text:0000000180005FD0                 mov     r14,[rsp+28h+arg_0]
.text:0000000180005FD5
.text:0000000180005FD5 loc_180005FD5:                          ; CODE XREF: CR_maybeParseWithLambda+8A↓j
.text:0000000180005FD5                                         ; DATA XREF: .pdata:0000000180483888↓o ...
.text:0000000180005FD5                 mov     rbx,[rsp+28h+arg_8]
.text:0000000180005FDA                 mov     rbp,[rsp+28h+arg_10]
.text:0000000180005FDF                 mov     rsi,[rsp+28h+arg_18]
.text:0000000180005FE4                 add     rsp,20h
.text:0000000180005FE8                 pop     rdi
.text:0000000180005FE9                 retn

解决方法

  1. 既然反汇编是call qword ptr [rax],那我把c中的伪代码翻译成result = lambda();不就可以了吗?

没有。反编译器检测到传入的变量很可能是被调用函数的参数。

例如,void f()void f(int) 函数都是用单个 call 汇编命令调用的,除了在后一种情况下,调用者将 int 值移动到在调用函数之前适当的寄存器。

您可以更改 lambda 的类型以避免这种情况。

  1. 为什么在伪代码中函数将自身作为参数?

非常仔细阅读汇编代码和反编译代码。 lambda 不是函数指针,要从中获取函数指针,必须取消引用两次。所以它可能是这样的(伪C++代码)

using FunctionType=int(int);
struct B{
    FunctionType* functionPointer;
};
struct A{
    B* b;
};
A* lambda; // the variable name is a little misleading,given this interpretation.
auto functionPointer=(*(*lambda).b);
functionPointer(lambda);

鉴于双重取消引用,很可能 B 实际上是一个 vftable(尽管在这些情况下,该函数通常使用 __thiscall 约定调用)——因此代码可以这样写:

struct Base{
    virtual void someFunction(){}
    virtual void otherFunction(){}
};
struct Base_vftableType{ // compiler-generated
    void (*someFunction)(Base*); // explicit (this) argument shown
    void (*otherFunction)(Base*); // explicit (this) argument shown
};
struct Derived: Base{
    Base_vftableType *vftable; // compiler-generated
    void someFunction(){ /* ... */ }
};
Base_vftableType derived_vftable{ /* ... */ }; // compiler-generated vftable

Derived *a;

// the function call is something like this in pseudo-C
// (and probably how it will be displayed in IDA):
a->vftable->someFunction(a);
  1. 当有诸如 lambda + 8i64(即 call qword ptr [rax+8])之类的调用时会发生什么?

同样,vftable 中可以有多个函数,而 + 只是简单地获取其他函数的地址。

假设是 64 位函数指针,+8 将是表中的第二个函数。

另见:c++ - How to organize vtables in IDA Pro? - Reverse Engineering Stack Exchange

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res