如何从char*buffer执行加载到内存中的代码?

Tho*_*yle -2 c c++ memory gcc

我试图从我们的代码库中提取一些函数,以便它们可以加密存储.text,然后只能使用正确的许可证密钥进行解密和访问.为此,我们需要(1)提取函数,(2)加载函数和(3)成功执行函数.

为了提取函数,我们依赖于gcc将函数放在彼此之后似乎有效,因为它FUNCTION_LENGTH似乎导致了正确的长度.但到目前为止,我一直无法加载函数并成功执行它们,我遇到了一个没有可理解信息的分段错误.

如何执行从char* buffer?加载到内存中的代码?

example.cpp

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

#define _FNAME_CAT(name, suffix) name##suffix
#define FNAME_CAT(name, suffix) _FNAME_CAT(name, suffix)

#define FUNCTION_START(ftype, fname, ...) \
    typedef ftype (*FNAME_CAT(func_, fname))(__VA_ARGS__); \
    ftype fname(__VA_ARGS__)

#define FUNCTION_END(ftype, fname) \
    void FNAME_CAT(fname, _end)() { }

#define FUNCTION_LENGTH(fname) \
    (int) ((intptr_t) FNAME_CAT(fname, _end) - (intptr_t) fname)

FUNCTION_START(void, test, int a, int b) {
    printf("a(%d), b(%d)\n", a, b);
} FUNCTION_END(void, test);

char* function_code(void* func, int flen) {
    return (char*) malloc(flen * sizeof(char));
}

void* function_create(const char* buffer, int blen) {
    void* func = mmap(0, blen, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_PRIVATE | MAP_ANON, -1, 0);
    return memcpy(func, buffer, blen);
}

int main(int argc, char** argv) {
    char* code = function_code((void*) test, FUNCTION_LENGTH(test));
    void* func = function_create((const char*) code, FUNCTION_LENGTH(test));

    ((func_test) test)(1, 2);
    ((func_test) func)(1, 2); // Program received signal SIGSEGV, Segmentation fault.

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

调试输出

(gdb) p FUNCTION_LENGTH(test)
$2 = 42
(gdb) n
[New Thread 5920.0x282c]
a(1), b(2)
16ew Thr    ((func_test) func)(1, 2);
(gdb) s
0x000006ffffff0000 in ?? ()
(gdb)
Cannot find bounds of current function
Run Code Online (Sandbox Code Playgroud)

Ben*_*igt 6

你的第一个问题是你实际上并没有真正使用这个func参数function_code......来自你指定函数的代码字节永远不会进入缓冲区.

但是修复它不会让你走得太远,因为整个方法存在很大问题.C或C++标准无法保证函数在内存中以与源代码相同的顺序排列......实际上在任何具有任何关于优化的线索的工具链上,它们都不会.

我建议你使用gcc特定的pragma将函数放在特定的代码段中以分离感兴趣的函数,然后从可执行文件中存储和删除该段.作为一个单元对整个段执行加密/解密,而不是试图找出各个函数的开始和结束位置.

请注意,未加密的代码将在内存中可用,熟练的反向器肯定会找到它.因为您不知道自己在做什么,所以您可能已经花费了更多时间来排除功能长度代码,而不是逆向工程师花费在解密字节上.代码的运行时解密对于打包者来说非常常见,并且具有执行访问权限的动态分配将像一个明亮的信标一样突出./proc/ pid /maps