繁体   English   中英

C - 如何在代码段中创建模式以在内存转储中识别它?

[英]C - How to create a pattern in code segment to recognize it in memory dump?

我转储我的RAM(它的一部分 - 仅代码段),以便找到放置C函数的位置。 我没有map文件,我不知道boot / init例程究竟是做什么的。

我将程序加载到RAM中,然后如果我转储RAM,很难找到确切的功能在哪里。 我想在C源代码中使用不同的模式,以便在内存转储中识别它们。

我尝试使用包含函数名称的不同第一个变量来启动每个函数,例如:

char this_function_name[]="main";

但它不起作用,因为此字符串将放在数据段中。

我有简单的16位RISC CPU和实验专有编译器(没有GCC或任何众所周知的)。 系统具有16Mb的RAM,与其他应用程序共享(引导加载程序,下载程序)。 几乎不可能找到一个独特的N NOP或smth序列。 像0xABCD。 我想在RAM中找到所有函数,所以我需要在RAM-dump中可见的唯一函数标识符。

什么是代码段的最佳模式?

如果是我,我会使用符号表,例如“nm a.out | grep main”。 获取您想要的任何功能的真实地址。

如果你真的没有符号表,那就自己做吧。

struct tab {
    void *addr;
    char name[100];  // For ease of searching, use an array.
} symtab[] = {
    { (void*)main, "main" },
    { (void*)otherfunc, "otherfunc" },
};

搜索名称,地址将紧接在其之前。 转到地址。 ;-)

如果您的编译器具有内联asm,则可以使用它来创建模式。 编写一些NOP指令,您可以通过内存转储中的操作码轻松识别这些指令:

MOV r0,r0
MOV r0,r0
MOV r0,r0
MOV r0,r0

数字常量放在代码段中,在函数说明中编码。 所以你可以尝试使用魔术数字,如0xDEADBEEF等。

即这是使用Visual C ++的简单C函数的反汇编视图:

void foo(void)
{
00411380  push        ebp  
00411381  mov         ebp,esp 
00411383  sub         esp,0CCh 
00411389  push        ebx  
0041138A  push        esi  
0041138B  push        edi  
0041138C  lea         edi,[ebp-0CCh] 
00411392  mov         ecx,33h 
00411397  mov         eax,0CCCCCCCCh 
0041139C  rep stos    dword ptr es:[edi] 
    unsigned id = 0xDEADBEEF;
0041139E  mov         dword ptr [id],0DEADBEEFh 

您可以看到0xDEADBEEF使其成为函数的源代码。 请注意,您在可执行文件中实际看到的内容取决于CPU的字节顺序(tx.Richard)。

这是一个x86示例。 但RISC CPU(MIPS等)具有将指令移动到寄存器中的指令 - 这些指令也可以具有特殊的可识别值(尽管MIPS只有16位,IIRC)。


Psihodelia - 抓住你的意图变得越来越难。 它只是您想要找到的单一功能吗? 那么你不能一个接一个地放置5个NOP并寻找它们吗? 你控制编译器/汇编器/链接器/加载器吗? 您可以使用哪些工具?

如你所说,这个:

char this_function_name[]="main";

...最终会将堆栈中的指针设置为包含该字符串的数据段。 但是,这个:

char this_function_name[]= { 'm', 'a', 'i', 'n' };

...可能会将所有这些字节放在您的堆栈中,这样您就能够识别代码中的字符串(我只是在我的平台上尝试过)。

希望这可以帮助

如何找到一个完全不同的方法来解决你的真正问题,即找到一个特定的代码块:使用diff。

使用所包含的函数编译一次代码,并将其注释掉一次。 生成两者的RAM转储。 然后,区分两个转储以查看更改的内容 - 这将是新的代码块。 (您可能必须对转储进行某种处理以删除内存地址以获得干净的差异,但在任何一种情况下,指令的顺序应该相同。)

为什么不让每个函数转储自己的地址。 像这样的东西:

void* fnaddr( char* fname, void* addr )
{
    printf( "%s\t0x%p\n", fname, addr ) ;
    return addr ;
}


void test( void )
{
    static void* fnaddr_dummy = fnaddr( __FUNCTION__, test ) ;
}

int main (int argc, const char * argv[]) 
{
    static void* fnaddr_dummy = fnaddr( __FUNCTION__, main ) ;
    test() ;
    test() ;
}

通过使fnaddr_dummy为静态,转储每个函数执行一次。 显然,您需要调整fnaddr()以支持您在系统上的任何输出或日志记录方式。 不幸的是,如果系统执行延迟初始化,您将只获得实际调用的函数的地址(这可能足够好)。

您可以通过调用相同的虚函数来启动每个函数,如:

void identifyFunction(unsigned int identifier){}

您的每个函数都会使用不同的参数(1,2,3,...)调用identifyFunction函数。 这不会给你一个神奇的mapfile,但是当你检查代码转储时,你应该能够快速找到identifyFunction的位置,因为会有很多跳转到该地址。 接下来扫描那些跳转并在跳转之前检查以查看传递的参数。 然后你可以制作自己的mapfile。 使用一些脚本,这应该是相当自动的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM