您如何找出源代码中此指令的含义?至少,是否有可能找出该指令的基本块?可用的源代码),现在我必须找出该反汇编指令在源代码中映射到的内容/位置。
我们还假设我在编译时不使用任何优化标志。
我可能应该提到我使用Intel的PIN作为发出这些反汇编指令的应用程序。因此,我知道这些指令属于哪个函数/例程。但是,我只是想在组装一级更加精确。
感谢您的帮助/提示!
#1 楼
您必须阅读并解释程序集。没有什么可以代替读取程序集。如果您知道汇编指令的含义,并且拥有源代码,那么两者之间的关系应该很清楚。没有直接的标记可以告诉装配体来自哪一行。因此,了解C / C ++中的基本结构在ASM中的外观。
循环是什么样的? (提示:有几种方法可以在ASM中编写循环)
结构是什么样的?
函数是什么样的?
指针是什么样的?
如果您对ASM的学习很好,那么一切都会很清楚。
另外,学习编译器如何工作,并学习调试运行的代码。
编辑:
您实际上可以生成调试器符号,以将代码与各个行号相关联,所以我上面所说的并不完全正确。
评论
“没有直接的标记可以告诉装配体来自哪个生产线。” -鉴于他可以从其源代码生成符号,所以情况并非如此。
–詹森·格夫纳(Jason Geffner)
2014年7月2日在15:34
他可以。我以为只是想在不给自己提示的情况下与大会合作。我编辑了帖子以反映真相。
–baordog
2014年7月2日15:41
#2 楼
编辑:下面的答案是特定于PE文件的,因为@Achilles指定他的问题是关于ELF文件的,所以它没有回答上面的问题。可以为您的程序生成符号,您可以使用Debug Interface Access SDK将汇编代码指令地址映射到源代码行号。特别是,您可能想使用IDiaLineNumber类。以下函数显示函数中使用的行号
(由
pSymbol
表示)。void dumpFunctionLines( IDiaSymbol* pSymbol, IDiaSession* pSession ) {
ULONGLONG length = 0;
DWORD isect = 0;
DWORD offset = 0;
pSymbol->get_addressSection( &isect );
pSymbol->get_addressOffset( &offset );
pSymbol->get_length( &length );
if ( isect != 0 && length > 0 )
{
CComPtr< IDiaEnumLineNumbers > pLines;
if ( SUCCEEDED( pSession->findLinesByAddr(
isect,
offset,
static_cast<DWORD>( length ),
&pLines)
)
)
{
CComPtr< IDiaLineNumber > pLine;
DWORD celt = 0;
bool firstLine = true;
while ( SUCCEEDED( pLines->Next( 1, &pLine, &celt ) ) &&
celt == 1 )
{
DWORD offset;
DWORD seg;
DWORD linenum;
CComPtr< IDiaSymbol > pComp;
CComPtr< IDiaSourceFile > pSrc;
pLine->get_compiland( &pComp );
pLine->get_sourceFile( &pSrc );
pLine->get_addressSection( &seg );
pLine->get_addressOffset( &offset );
pLine->get_lineNumber( &linenum );
printf( "\tline %d at 0x%x:0x%x\n", linenum, seg, offset );
pLine = NULL;
if ( firstLine )
{
// sanity check
CComPtr< IDiaEnumLineNumbers > pLinesByLineNum;
if ( SUCCEEDED( pSession->findLinesByLinenum(
pComp,
pSrc,
linenum,
0,
&pLinesByLineNum)
)
)
{
CComPtr< IDiaLineNumber > pLine;
DWORD celt;
while ( SUCCEEDED( pLinesByLineNum->Next( 1, &pLine, &celt ) ) &&
celt == 1 )
{
DWORD offset;
DWORD seg;
DWORD linenum;
pLine->get_addressSection( &seg );
pLine->get_addressOffset( &offset );
pLine->get_lineNumber( &linenum );
printf( "\t\tfound line %d at 0x%x:0x%x\n", linenum, seg, offset );
pLine = NULL;
}
}
firstLine = false;
}
}
}
} }
评论
抱歉,我忘了提,我需要在Linux上执行此操作。
–阿喀琉斯
2014年7月2日在15:35
这不是完全正确的,取决于是否可以完美地复制构建。如果二进制文件是经过PGO优化的,那么我认为没有机会。更不用说具有相同版本的编译器和构建环境。
–德米特里·雅努什凯维奇(Dmitry Janushkevich)
2014年7月2日在15:36
我以为他在看他自己创造的建筑。我还认为这是在Windows上:)
–詹森·格夫纳(Jason Geffner)
2014年7月2日在16:13
#3 楼
如何弄清楚该指令在源代码中的含义?
大多数是直觉和经验。从源代码的高级概述来看,可以发现该功能以及该指令所属的行,但是到目前为止,我还不知道可以执行相同操作的程序。拥有调试信息当然可以帮助很多,但不是万能的,而且通常也不总是可用的。该指令来自哪里?
一般来说,不是。在某些情况下,是的。现代编译器倾向于过于积极地优化代码。即使具有编译器生成的所有调试信息,有时也不足以映射给定insn的精确位置,这可以通过尝试在此类应用程序上进行源代码级调试来证明。没有适当地注意到您自己构建了二进制文件。然后,是的,应该至少可以在给定调试信息的情况下将指令映射到函数。
#4 楼
您正在使用哪个编译器?我的背景更多是Windows开发(而不是Linux / BSD / OSX),所以我只能说这种情况。但是在Visual Studio中,您可以在调试C /时看到生成的程序集C ++。有关详细信息,请参见此MSDN文章。
如果您仅对ASM感兴趣,则可能需要更改Visual Studio项目中的某些编译设置,以减少项目中包含的调试信息。有关如何执行此操作的详细信息在这里。
主要涉及:
禁用C ++异常
设置为程序数据库(/ Zi)的调试信息格式
关闭缓冲区安全性检查(/ GS-)
关闭增量链接(/ NCREMENTAL:NO)
Embarcadero C ++ Builder和Delphi (以前为Borland)也提供相同的功能。用法详细信息在这里。
#5 楼
如果您自己进行编译,并且可以使用矮级信息进行编译,则可以使用gnu binutils中的addr2line。如果您掌握的信息较少,那么我只会尝试打下基础,通常将对参数或函数调用的引用用作主要地标。显然,这并不适用于每个二进制文件。
#6 楼
如果您有完整的可用资源。这是我建议的(当前正在做的):使用调试信息编译二进制文件并禁用优化。如果要编译某些
分布式代码,还请确保
禁止剥离二进制文件。这意味着:用gcc编译以下标志
(取决于所需的调试信息级别,我通常使用ggdb / ggdb3编译):
-g -O0 OR -ggdb -O0 OR -ggdb3 -O0
接下来,使用objdump创建二进制文件的转储: />转储并将其与源代码匹配。
评论
太棒了!谢谢!这完美而轻松地解决了我的问题。
–mackycheese21
18年11月25日在0:51
评论
我的旧问题可能以某种方式与您有关,而不是说它是重复的,只是提醒您:reverseengineering.stackexchange.com/questions/3166/…指令地址也可用吗?从上面的示例来看这不是很明显。
@DmitryYanushkevich是的,所有地址都可用。
你检查了吗?
我可以建议您一个非常有用的培训网站,其中包含许多小示例binary-auditing.com:随着难度的逐步提高,您将设法从ASM中提取各种HLL(高级语言)模式。它从变量分配开始,经历循环,条件,对象,结构等。