如何在编译后计算某些二进制函数(或基本块)的校验和?

时间:2017-02-28 17:32:49

标签: c++ security binary x86 obfuscation

我想编写一些简单的防篡改机制,在运行时计算某些函数(或基本块)的校验和,并将其与固定的预计算值进行比较。如果校验和匹配,那么一切都很好;否则程序终止。

我可以在运行时轻松计算校验和,但我不知道如何计算固定值以进行比较。

我想我在编译后对二进制文件进行了一些后期处理,因为在编译时不可能知道校验和(对吧?)。

但是如何在二进制代码中找到与我的函数(或基本块)对应的代码点?我可以使用一些十六进制编辑器手动执行此操作,但我希望自动执行此过程。在预先计算了校验和后,我需要修改二进制文件以包含它 - 但这又要求能够在二进制文件中找到正确的位置。

对解决方案的任何建议?

2 个答案:

答案 0 :(得分:0)

例如,您可以获得指向函数的指针并将其重新解释为uint8_t的数组。如果您不希望编译器在某个循环中使用该函数的内联副本,您也可以禁用特定函数的内联。

uint8_t* pMain = (uint8_t*)&main;

然后你必须尝试估计函数长度并计算校验和。

答案 1 :(得分:0)

如果您的代码包含多个文件,您可以遵循以下机制:

  1. 使用您希望将来检查的功能编译文件

  2. 找到已编译的文件(最可能是.o,.obj)函数位置 - 例如使用objdump或类似工具 - 它必须显示人类可读文本以及编译代码的十六进制代码

    < / LI>

    示例:

      

    objdump a.o -d --insn-width = 10

      40064b:       48 89 e5                        mov    %rsp,%rbp
      40064e:       ff d0                           callq  *%rax
      400650:       5d                              pop    %rbp
      400651:       e9 7a ff ff ff                  jmpq   4005d0 <register_tm_clones>
    
    0000000000400656 <calculate>:
      400656:       55                              push   %rbp
      400657:       48 89 e5                        mov    %rsp,%rbp
      40065a:       89 7d ec                        mov    %edi,-0x14(%rbp)
      40065d:       48 89 75 e0                     mov    %rsi,-0x20(%rbp)
      400661:       8b 05 f9 09 20 00               mov    0x2009f9(%rip),%eax        # 601060 <magicCRC1>
      400667:       89 c2                           mov    %eax,%edx
      400669:       48 8b 45 e0                     mov    -0x20(%rbp),%rax
      40066d:       89 10                           mov    %edx,(%rax)
      40066f:       48 8b 45 e0                     mov    -0x20(%rbp),%rax
      400673:       48 83 c0 04                     add    $0x4,%rax
      400677:       c7 00 01 00 00 00               movl   $0x1,(%rax)
      40067d:       c7 45 fc 00 00 00 00            movl   $0x0,-0x4(%rbp)
      400684:       eb 72                           jmp    4006f8 <calculate+0xa2>
      400686:       83 7d fc 01                     cmpl   $0x1,-0x4(%rbp)
      40068a:       75 1c                           jne    4006a8 <calculate+0x52>
      40068c:       8b 45 fc                        mov    -0x4(%rbp),%eax
      40068f:       48 98                           cltq   
    

    所以在objdump函数的情况下,name会被&lt;包围&GT; - 以上计算函数的例子

    1. 编写脚本来解析它 - 你需要在地址和反汇编代码之间使用十六进制代码

    2. 计算你的CRC,哈希或任何你需要的东西

    3. 存储CRC以及块长度以便稍后在运行时解码它在一个文件中也将被编译 - 当然你需要知道映射什么变量/常量保持哪个函数CRC

    4. 链接所有文件

    5. 如果单个文件可用(完整的可执行文件),您可以:

      1. 在源代码中定义常量/静态以保存CRC
      2. 如上所述进行CRC计算
      3. 以二进制(在.data或.rodata部分中)找到您的var位置并更新它
      4. 你很可能还需要修复可执行CRC!