混淆函数调用

2024-03-24

John Viega 在他的《Secure Programming Cookbook for C and C++》一书中提出了一种混淆函数调用的方法。可以读取here http://etutorials.org/Programming/secure+programming/Chapter+12.+Anti-Tampering/12.9+Using+Function+Pointers/.

#define SET_FN_PTR(func, num)                  \
    static inline void *get_##func(void) { \
      int  i, j = num / 4;                 \
      long ptr = (long)func + num;         \
      for (i = 0;  i < 2;  i++) ptr -= j;  \
      return (void *)(ptr - (j * 2));      \
    }
#define GET_FN_PTR(func) get_##func(  )

#include <stdio.h>

void my_func(void) {
  printf("my_func(  ) called!\n");
}

SET_FN_PTR(my_func, 0x01301100); /* 0x01301100 is some arbitrary value */

int main(int argc, char *argv[  ]) {
  void (*ptr)(void);

  ptr = GET_FN_PTR(my_func);     /* get the real address of the function */
  (*ptr)(  );                      /* make the function call */
return 0;

}

我用它编译了gcc fp.c -S -O2,Ubuntu 15.10 64位,gcc 5.2.1,并检查了程序集:

...
my_func:
.LFB23:
        .cfi_startproc
        movl    $.LC0, %edi
        jmp     puts
        .cfi_endproc
.LFE23:
        .size   my_func, .-my_func
        .section        .text.unlikely
.LCOLDE1:
        .text
.LHOTE1:
        .section        .text.unlikely
.LCOLDB2:
        .section        .text.startup,"ax",@progbits
.LHOTB2:
        .p2align 4,,15
        .globl  main
        .type   main, @function
main:
.LFB25:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        call    my_func
        xorl    %eax, %eax
        addq    $8, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
...

我看到 my_func 被调用main。有人可以解释一下这个方法如何混淆函数调用吗?

我看到很多读者只是过来投反对票。我花了一些时间来理解这个问题,并且当我未能将其发布在这里时。请至少写一些评论,而不是按下否决按钮。

更新:关闭优化我得到:

...
my_func:
...
get_my_func:
...
main:
...
    call    get_my_func
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    call    *%rax
...

我认为现在没有内联。但我真的不明白为什么它很重要......

我仍在寻找解释作者使用此代码的目标是什么,即使它不适用于当今的智能编译器。


建议方法的想法是使用间接函数调用,以便必须首先计算函数地址,然后再调用。 C 预处理器用于提供一种为实际函数定义代理函数的方法,该代理函数提供确定代理函数提供访问的实际函数的实际地址所需的计算。

See 维基百科文章代理模式 https://en.wikipedia.org/wiki/Proxy_pattern有关代理设计模式的详细信息,其中有这样一句话:

代理设计模式允许您向其他人提供接口 通过创建包装类作为代理来获取对象。包装类, 这是代理,可以向对象添加附加功能 兴趣而不改变对象的代码。

我建议采用一种替代方案,它实现相同类型的间接调用,但它不需要使用 C 预处理器来隐藏实现细节,从而使源代码的阅读变得困难。

C 编译器允许struct包含函数指针作为成员。这样做的好处是,您可以使用函数指针 a 成员定义外部可见的结构变量,但在定义该结构时,可以在结构变量定义中指定的函数static这意味着它们仅具有文件可见性(请参阅C程序中的“静态”是什么意思 https://stackoverflow.com/questions/572547/what-does-static-mean-in-a-c-program.)

所以我可以有两个文件,一个头文件 func.h 和一个实现文件 func.c ,它们定义了struct类型、外部可见结构变量的声明、与 a 一起使用的函数static修饰符,以及带有函数地址的外部可见结构变量定义。

这种方法的吸引力在于源代码易于阅读,并且大多数 IDE 会更好地处理这种间接代码,因为 C 预处理器不用于在编译时创建源代码,这会影响人们和软件工具(例如作为 IDE。

示例 func.h 文件将使用函数 #included 到 C 源文件中,如下所示:

// define a type using a typedef so that we can declare the externally
// visible struct in this include file and then use the same type when
// defining the externally visible struct in the implementation file which
// will also have the definitions for the actual functions which will have
// file visibility only because we will use the static modifier to restrict
// the functions' visibility to file scope only.
typedef struct {
    int (*p1)(int a);
    int (*p2)(int a);
} FuncList;

// declare the externally visible struct so that anything using it will
// be able to access it and its members or the addresses of the functions
// available through this struct.
extern FuncList myFuncList;

func.c 文件示例可能如下所示:

#include <stdio.h>

#include "func.h"

// the functions that we will be providing through the externally visible struct
// are here.  we mark these static since the only access to these is through
// the function pointer members of the struct so we do not want them to be
// visible outside of this file. also this prevents name clashes between these
// functions and other functions that may be linked into the application.
// this use of an externally visible struct with function pointer members
// provides something similar to the use of namespace in C++ in that we
// can use the externally visible struct as a way to create a kind of
// namespace by having everything go through the struct and hiding the
// functions using the static modifier to restrict visibility to the file.

static int p1Thing(int a)
{
    return printf ("-- p1 %d\n", a);
}

static int p2Thing(int a)
{
    return printf ("-- p2 %d\n", a);
}

// externally visible struct with function pointers to allow indirect access
// to the static functions in this file which are not visible outside of
// this file.  we do this definition here so that we have the prototypes
// of the functions which are defined above to allow the compiler to check
// calling interface against struct member definition.
FuncList myFuncList = {
    p1Thing,
    p2Thing
};

使用此外部可见结构的简单 C 源文件可能如下所示:

#include "func.h"

int main(int argc, char * argv[])
{
    // call function p1Thing() through the struct function pointer p1()
    myFuncList.p1 (1);
    // call function p2Thing() through the struct function pointer p2()
    myFuncList.p2 (2);
    return 0;
}

Visual Studio 2005 为上述内容生成的汇编程序main()如下所示,显示了通过指定地址的计算调用:

; 10   :    myFuncList.p1 (1);

  00000 6a 01        push    1
  00002 ff 15 00 00 00
    00       call    DWORD PTR _myFuncList

; 11   :    myFuncList.p2 (2);

  00008 6a 02        push    2
  0000a ff 15 04 00 00
    00       call    DWORD PTR _myFuncList+4
  00010 83 c4 08     add     esp, 8

; 12   :    return 0;

  00013 33 c0        xor     eax, eax

正如您所看到的,此函数调用现在是通过结构内的偏移量指定的结构的间接函数调用。

这种方法的好处是,您可以对包含函数指针的内存区域执行任何您想要的操作,只要在通过数据区域调用函数之前,正确的函数地址已放在那里即可。因此,您实际上可以有两个函数,一个函数用正确的地址初始化该区域,第二个函数清除该区域。因此,在使用这些函数之前,您将调用该函数来初始化该区域,并在使用该函数之后调用该函数来清除该区域。

// file scope visible struct containing the actual or real function addresses
// which can be used to initialize the externally visible copy.
static FuncList myFuncListReal = {
    p1Thing,
    p2Thing
};

// NULL addresses in externally visible struct to cause crash is default.
// Must use myFuncListInit() to initialize the pointers
// with the actual or real values.
FuncList myFuncList = {
    0,
    0
};

// externally visible function that will update the externally visible struct
// with the correct function addresses to access the static functions.
void myFuncListInit (void)
{
    myFuncList = myFuncListReal;
}

// externally visible function to reset the externally visible struct back
// to NULLs in order to clear the addresses making the functions no longer
// available to external users of this file.
void myFuncListClear (void)
{
    memset (&myFuncList, 0, sizeof(myFuncList));
}

所以你可以做这样的修改main():

myFuncListInit();
myFuncList.p1 (1);
myFuncList.p2 (2);
myFuncListClear();

然而,您真正想做的是打电话给myFuncListInit()位于源代码中不靠近实际使用函数的位置。

另一个有趣的选择是对数据区域进行加密,为了使用该程序,用户需要输入正确的密钥来正确解密数据以获得正确的指针地址。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

混淆函数调用 的相关文章

  • 不允许从函数返回函数。我怎么能?

    8 3 5 8 Functions dcl fct says 函数的返回类型不得为 类型数组或function 尽管它们可能具有指针类型的返回类型或对此类事物的引用 为什么规则这么明确 是否有某种语法甚至允许返回函数而不是函数指针 我是否误
  • 如何通过MFC将应用程序设置保存到注册表中?

    我有一个由 MFC 项目向导创建的 MFC 应用程序 我想在注册表中保存 读取应用程序设置 所以问了这个question https stackoverflow com questions 1880275 good c registry w
  • 在 C/C++ 中读取和写入二进制文件的中间部分

    如果我有一个大的二进制文件 假设它有 100 000 000 个浮点数 C 或 C 有没有办法打开文件并读取特定的浮点数 而不必将整个文件加载到内存中 即我如何快速找出第 62 821 214 个浮点是什么 第二个问题 有没有办法更改文件中
  • IssuerSigningKeyResolver 调用异步方法

    我们使用 IssuerSigningKeyResolver 它是 Microsoft IdentityModel Tokens 的一部分 用于令牌验证并接受非异步委托 我们调用一个异步方法 这将导致阻塞调用 因此想知道使用它的正确方法是什么
  • 当 TestCase 包含数组时,NUnit 无法识别该 TestCase

    这是我在 NUnit 中遇到的非常简单但烦人的行为 我有一些这样的测试 Test TestCase 1 2 hello TestCase 3 5 goodbye public void MyClass MyMethod int a int
  • 我是否必须使用我的数据库训练 Viola-Jones 算法才能获得准确的结果?

    我尝试提取面部数据库的面部特征 但我认识到 Viola Jones 算法在两种情况下效果不佳 当我尝试单独检测眼睛时 当我尝试检测嘴巴时 运作不佳 检测图像的不同部分 例如眼睛或嘴巴 或者有时会检测到其中几个 这是不可能的情况 我使用的图像
  • 验证码怎么写?

    我正在开发一个注册表 我想放置验证码 我生成一个随机字符串 但如何将其转换为图像 否则我如何开发验证码或任何参考 谢谢 Try out 验证码 http recaptcha net plugins aspnet 或查看博客文章 使用 Asp
  • 如何在 ASP.NET 5/vNext/Core 中使用 Elmah?

    我对如何在 ASP NET 5 MVC 6 项目中使用 Elmah 有点困惑 我从 nuget 得到了包 它添加了 Elmah Mvc 2 1 2 到project json 中的依赖项 我不知道从这里到哪里去 以前 nuget 会向 we
  • DPI 图形屏幕分辨率像素 WinForm PrintPageEventArgs

    对于运行我的应用程序的任何显示器 Dpi 点与像素有何关系 int points Screen primary public Form1 InitializeComponent points 1 primary null void OnPa
  • 如何使用 PowerShell 使用 C# DLL 中存在的类的 New-Object

    例如 我有一个 C 类 public class MyComputer PSObject public string UserName get return userName set userName value private strin
  • 如何获得字符串的所有字谜

    我试图找到一个字符串的所有可能的字谜并仅使用递归将它们存储在数组中 我被困住了 这就是我所拥有的一切 int main const int MAX 10 string a ABCD string arr 10 permute arr a 0
  • 如何将整个流读入 std::string ?

    我正在尝试将整个流 多行 读入字符串中 我正在使用这段代码 它有效 但它冒犯了我的风格感 当然有更简单的方法吗 也许使用字符串流 void Obj loadFromStream std istream stream std string s
  • 如何检测机器是否加入域?

    如何检测计算机是否已加入 Active Directory 域 相对于工作组模式 如果没有必要的话 不要用 pinvoke 来愚弄 参考System DirectoryServices 然后调用 System DirectoryServic
  • 弹出窗口或弹出窗口显示附加信息

    我想在我的应用程序顶部显示带有附加信息的弹出窗口 我的信息是Listview大约 500 个项目我都尝试过 有问题flyout gt 它里面可能有scrollViewer 所以我的列表视图不能正确虚拟化 其他一切都可以 有我的代码 Flyo
  • 如果键不是映射中的初始化键,STL map[key] 返回什么? [复制]

    这个问题在这里已经有答案了 这是一些示例代码 include
  • 如何使用 Xamarin 应用程序开发自动注销

    我必须在 App xaml cs 上添加功能才能使其正常工作 我在 OnStart 上添加了功能 但现在它会间歇性地一次又一次地将我从应用程序中注销 根据下面的代码 我需要做什么才能让它停止这样做 或者我的代码有问题 这是我最新的代码 na
  • 模板是如何实例化的?

    这是一个练习 来自C 入门第五版 练习 16 27 对于每个带标签的语句 解释什么 如果有 实例化发生 如果实例化了模板 请解释原因 如果 不 请解释为什么不 第677页 template
  • 在C中更改函数内的数组

    我正在学习 C 并且很困惑为什么在 main 中创建的数组不会在函数内部更改 我假设传递的数组是一个指针 并且更改指针应该更改数组 对吧 有人可以解释这种情况下发生了什么吗 谢谢你的帮助 int main int i length 10 i
  • 计算 .NET Core 项目的代码指标?

    我正在研究 ASP NET Core 和 NET Core 项目 对于经典的 C 项目 Visual Studio 2015 具有计算代码指标的功能 对于 NET Core 预览版 2 工具中缺少支持 在工具更加完整之前 有人知道解决方法吗
  • 为什么在嵌套类上调用方法时不调用父类的静态构造函数?

    给出以下代码 为什么在 Main 的第一行之后没有调用 Outer 的静态构造函数 namespace StaticTester class Program static void Main string args Outer Inner

随机推荐

  • C# - 哪个更快:String.Contains() 或 Regex.isMatch()? [复制]

    这个问题在这里已经有答案了 可能的重复 Regex IsMatch 与 string Contains https stackoverflow com questions 2962670 regex ismatch vs string co
  • 为什么 System.out.print 会导致自动刷新?

    System out 是一个 PrintStream 对象 我阅读了有关 PrintStream 的文档 我不明白的是为什么 System out print 会导致缓冲区被刷新 这种情况不应该只发生在 println 中吗 这种情况不应该
  • IndexError:读取 python 的 CSV 文件中的列表索引超出范围

    我有一个包含 30000000 个条目的 csv 文件 像这样 3 2 2 2 2 2 2 当我尝试颠倒词序时 我收到以下错误 Traceback most recent call last File home grpus dg py li
  • 如何在 CodeIgniter 中创建库类的多个实例?

    我想在 CodeIgniter 中创建一个类的多个实例 我已将我的类创建为一个库 但无法弄清楚用于创建多个实例的语法 来自 CodeIgniter 用户指南 CI 用户指南 加载器类 http codeigniter com user gu
  • 将 puppeteer 与 imgui-js 结合使用

    如果问题的长度可能很吓人 问题的摘要是如何从节点服务器与前端应用程序交互 我相信 Puppeteer 的使用应该伴随着该请求的解决 问题很大 因为我解释了我在浏览器中实现后端代码 傀儡师 工作的所有失败尝试 除了构建和运行存储库之外 尽管按
  • Android Fragment 中的 EditText 值不刷新

    我正在使用Viewpager在 3 之间切换fragments 一切工作正常 除了第二个选项卡的刷新 或fragment 在这个选项卡中 我有一张图片 一些静态的Textviews 一些动态TextViews还有一些EditText fie
  • 如何生成 pool_transactions_genesis 和domain_transactions_genesis?

    我正在尝试创建 Hyperledger Indy 网络 并且一直在遵循阅读文档 https hyperledger indy readthedocs io projects node en latest start nodes html 我
  • 在 SQL 中的 CAST 中使用 & 符号

    SQL Server 2005 上的以下代码片段在与号 上失败 select cast
  • 在两个片段之间拖放

    我正在研究用户界面上同时可见的两个不同片段之间的拖放操作 我想将视图从一个片段拖到另一个片段中 我可以在片段之间拖动它 但我面临的不好的是我无法在第二个片段上监听 onDrag 以获取第一个片段的视图 简而言之 第二个片段上的 OnDrag
  • 如何将 Play 与自定义模块和持续集成结合使用

    如何在 CI 系统中设置 Play 应用程序和 自定义 Play 模块的构建 以便当模块的构建良好时 构建会将模块工件安装在本地存储库中和 或将它们部署到远程存储库 并且应用程序使用该存储库中的工件 该解决方案也应该适合在本地工作的开发人员
  • Android 应用内计费 v3:“无法执行操作:queryInventory”

    我第一次使用新的 v3 API 设置应用内结算 它在我的设备上运行正常 但我收到了其他用户的很多错误报告 其中之一是 java lang IllegalStateException IAB helper is not set up Can
  • 如何定义,系统中DEP为ON

    德尔福Xe XP Vista Win7 WAR 2008R2 0 支持DEP 数据执行保护 CPU Function isCpuDEP bool begin Result end 1 如何定义系统中DEP为ON Function isEna
  • 无法获取用户列表[重复]

    这个问题在这里已经有答案了 我想在我的应用程序中显示用户列表 我使用默认的Auth来自 firebase 的系统 但回复总是空的 FIRDatabase database reference child users queryOrdered
  • 如何检查 JavaScript 对象是否是 DOM 对象?

    我试图得到 document createElement div gt true tagName foobar something gt false 在我自己的脚本中 我曾经只使用它 因为我从来不需要tagName作为财产 if objec
  • 拖动 D3 节点时防止单击操作

    我可以单击 D3 节点来获取alert 信息 我也可以拖动 D3 节点 但拖动也会在释放鼠标时触发单击行为 有没有办法阻止拖动节点后的点击行为 这就是我所说的拖动 var node svg selectAll node data graph
  • 使用 clickonce 在 C# 解决方案中部署外部文件

    我在使用 Visual Studio Express 2010 c 版本时遇到问题 我有一个引用 DLL 的项目 该 DLL 有一个外部 Excel 文件标记为 构建行动 内容 复制到输出目录 始终复制 当我构建解决方案时 此 Excel
  • 矢量形式的垂直风可视化

    我有屏蔽数组格式的垂直风数据 我想将其绘制成矢量形式 masked array data 4 06932000e 04 4 06932000e 04 5 70601827e 04 2 43262173e 04 2 43262173e 04
  • Visual SVN Server:提交前/提交后挂钩指南

    考虑到这里的评论 这可能是最好的维基百科 分享常用 有用的 SVN 预提交钩子 https stackoverflow com questions 884608 share common useful svn pre commit hook
  • 为什么 set::find 不是模板?

    模板函数来自
  • 混淆函数调用

    John Viega 在他的 Secure Programming Cookbook for C and C 一书中提出了一种混淆函数调用的方法 可以读取here http etutorials org Programming secure