【问题标题】:Android Self-modifying code - NDKAndroid自修改代码-NDK
【发布时间】:2014-02-06 04:49:57
【问题描述】:

我正在尝试制作一个自我修改的代码库,我已经满脑子都是,我有以下代码:

typedef int (*FUNC) (void);
int test();

JNIEXPORT int Java_com_example_untitled_MyActivity_decrypt( JNIEnv* env, jobject thiz)
{
    void *code = mmap(NULL, 4, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (code != MAP_FAILED) {
        memcpy(code, test, 4);

        return ( (FUNC)code)();
    }

    return 0;
}

int test()
{
    return 100;
}

请帮助...我使用Native self-modifying code on Android 作为我的起点,他们说了一些关于使用“-marm”和拇指位进行编译...

我遇到的问题是,它只是崩溃了。我试过使用 cacheflush 功能,似乎没有帮助。我很茫然。

【问题讨论】:

  • 你有什么问题?您的代码的预期行为和观察到的行为是什么? (例如,为什么你认为 test 正好是 4 个字节长?)
  • 因为我对 ARM 进行了逆向工程,并且知道 mov r0,100 是 2 个字节,而 BX LR 是 2 个字节...:) 还验证了它没有使用 4 字节 mov 指令。
  • ARM 指令长度为 4 个字节...
  • 不,并非总是如此。我用 IDA 检查过,它们每条指令只有 2 个字节。我对 Android 游戏进行了逆向工程,并使用 2 字节和 4 字节指令在 ARM 中修改了其中的 100 多个。
  • 对我来说听起来像 Thumb,而不是 ARM。要从 Thumb 调用到 ARM,或从 ARM 到 Thumb,需要进行指令集交换(BLX 而不是 BL)。一个两字节的 BX LR 指令是从 thumb code 到 ARM 的返回;但是调用者需要知道通过模式更改来调用(或者只是坚持使用 ARM 并使其变得简单)。

标签: android android-ndk self-modifying


【解决方案1】:

在 ARM 上,您需要刷新 CPU 缓存,以确保您刚刚复制的指令在执行之前对 CPU 是可见的。一个简单的方法是:

#include <unistd.h>  // for cacheflush()

...

// Copy the instructions to the destination address.
memcpy(dest, original_intructions, size_of_instructions);

// Clear the CPU cache
cacheflush((uintptr_t)dest, (uintptr_t)dest + size_of_instructions, 0);

// Run them.
return ((FUNC)dest)();

【讨论】:

  • 这不是直接的问题。问题正如addaon所说。也许你可以回答我这个问题,我可以编译一个函数,获取 ARM,删除该函数并仍然使用 ARM 并将参数传递给它吗?或者 ARM 是否使用会导致问题的内存地址?
  • 这取决于函数的编译方式。您需要先使用 -fPIC 来生成与位置无关的代码。其次,您需要确保该函数永远不会尝试访问全局变量或其他函数(两者都会引入重定位,从而阻止执行您想要的操作)。
  • 我最终只是使用 mprotect 修改了应用程序的内存,所以代码只是在 ida 中进行了混淆,使用 AES 和多级混淆。
猜你喜欢
  • 2015-09-15
  • 1970-01-01
  • 2011-05-26
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-29
相关资源
最近更新 更多