基本上,这就是我想知道的内容,如果您有反汇编的指令说:

您如何找出源代码中此指令的含义?至少,是否有可能找出该指令的基本块?可用的源代码),现在我必须找出该反汇编指令在源代码中映射到的内容/位置。

我们还假设我在编译时不使用任何优化标志。

我可能应该提到我使用Intel的PIN作为发出这些反汇编指令的应用程序。因此,我知道这些指令属于哪个函数/例程。但是,我只是想在组装一级更加精确。

感谢您的帮助/提示!

评论

我的旧问题可能以某种方式与您有关,而不是说它是重复的,只是提醒您:reverseengineering.stackexchange.com/questions/3166/…

指令地址也可用吗?从上面的示例来看这不是很明显。

@DmitryYanushkevich是的,所有地址都可用。

你检查了吗?

我可以建议您一个非常有用的培训网站,其中包含许多小示例binary-auditing.com:随着难度的逐步提高,您将设法从ASM中提取各种HLL(高级语言)模式。它从变量分配开始,经历循环,条件,对象,结构等。

#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