[英]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.