-
-
[翻译]Debugging/Reversing NT System Binaries
-
发表于: 2007-12-3 15:24 5632
-
[翻译]Debugging/Reversing NT System Binaries
来自913K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3!0H3k6h3&6J5j5$3g2Q4x3X3g2G2M7X3N6Q4x3V1k6T1L8r3!0Y4i4K6u0r3N6X3W2W2N6#2)9J5c8U0t1&6x3R3`.`.
作者:AlexIonescu
作者是reactos 的内核开发者,AlexIonescu 自己还有一个主页在0c6K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3q4D9k6i4S2Q4x3X3c8A6L8$3&6W2M7$3y4#2i4K6u0W2j5$3!0E0i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1&6i4K6R3%4i4K6S2o6i4@1f1&6i4K6W2p5i4@1p5J5i4@1f1@1i4@1t1&6i4K6W2r3i4@1f1&6i4K6R3K6i4@1u0p5i4@1f1#2i4@1p5@1i4@1p5%4i4@1f1&6i4K6R3%4i4K6S2r3i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1#2i4@1p5#2i4@1u0p5i4@1f1@1i4@1t1^5i4K6W2o6i4@1f1^5i4@1p5#2i4@1u0r3i4@1f1K6i4K6R3H3i4K6R3J5i4@1f1@1i4@1u0n7i4K6V1$3i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1#2i4K6R3#2i4@1t1%4i4@1f1@1i4@1u0p5i4K6V1K6i4@1f1@1i4@1u0n7i4K6S2n7i4@1f1%4i4@1u0n7i4K6S2p5i4@1f1K6i4K6R3H3i4K6R3J5
5bcK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8X3u0D9L8$3N6K6i4K6u0r3j5h3c8$3k6r3u0Y4i4K6g2X3M7%4W2K6N6r3g2E0i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5J5y4U0S2Q4x3X3g2S2M7%4m8^5
da3K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8X3u0D9L8$3N6K6i4K6u0r3j5h3c8$3k6r3u0Y4i4K6g2X3M7%4W2K6N6r3g2E0i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5K6y4U0W2Q4x3X3g2S2M7%4m8^5
9e5K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8W2!0q4y4q4!0n7z5g2)9&6c8W2!0q4y4W2)9&6z5q4!0m8c8W2!0q4y4q4!0n7z5q4!0m8b7g2!0q4y4q4!0n7z5q4)9^5c8q4!0q4z5g2)9&6y4q4)9&6z5g2!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4#2!0n7c8q4)9&6x3g2!0q4y4#2!0m8b7W2)9&6z5g2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4W2!0n7y4#2!0n7x3g2!0q4y4g2)9^5y4g2!0m8y4g2!0q4y4#2!0m8x3q4)9&6y4q4!0q4y4#2!0m8z5g2!0n7y4W2N6A6L8X3c8G2N6%4y4Q4c8e0g2Q4z5o6k6Q4z5o6g2Q4c8e0W2Q4z5o6y4Q4b7e0S2Q4c8e0g2Q4z5p5g2Q4z5f1k6Q4c8e0N6Q4z5e0m8Q4z5o6k6Q4c8e0N6Q4b7U0y4Q4b7V1u0Q4c8e0g2Q4z5o6S2Q4z5e0N6Q4c8e0S2Q4b7f1k6Q4b7V1g2Q4c8e0N6Q4b7e0S2Q4z5p5u0Q4c8e0N6Q4b7U0y4Q4b7V1u0Q4c8e0g2Q4z5o6S2Q4z5e0N6Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8e0k6Q4z5f1y4Q4z5o6W2Q4c8e0g2Q4z5o6N6Q4b7e0m8Q4c8e0S2Q4b7f1g2Q4b7U0u0Q4c8e0k6Q4z5e0S2Q4b7f1k6Q4c8e0N6Q4b7V1c8Q4z5e0q4Q4c8e0N6Q4b7f1u0Q4z5e0W2Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0N6Q4b7V1u0Q4b7U0c8Q4c8e0k6Q4z5p5q4Q4b7e0c8Q4c8e0S2Q4z5o6m8Q4z5o6g2Q4c8e0S2Q4b7f1g2Q4b7U0u0Q4c8e0N6Q4z5f1q4Q4z5o6b7`.
我觉得我应该在博客一开始就把这些小贴士放上……其中一些看起来是显而易见的,但是我发现很多逆向工程师并没有意识到这些会对NT系统的逆向和调试提供很大的方便。随意给我发送何额外的资源以便我能加上它们。
1)调试版本(Checked Builds)。
你得首先准备好它。如果你正在逆向一个发行版的二进制文件,请立即停下吧。你已经错过了大量的调试信息,断言和更容易读懂的代码。这里列举一些调试版本的优势:
*大多数情况下NT系统的调试版本都是免费。那是正确的,如果你想要比较不同版本的NT系统之间的区别,你不需要带上每个发行版本的CD(或者更遭,在因特网上面寻找)。NT Service Packs 包含所有你想逆向的系统内核文件,而且包括调试版本在内的NT Service Packs也是可以免费地下载的。现在,你可以免费地对Windows2003的二进制文件进行逆向了。
*读起来的容易得多的代码。调试版本编译的时候不会使用编译器的OMAP技术,OMAP技术会在编译的时候吧函数分割为不同的块并重新编排它们以方便CPU缓存它们。那意味着函数可以被线性和轻松地被逆向。
*调试信息输出。这个是很棒的东西。M$开发者正告诉你在他们的代码里发生着什么,因此你不必猜测这些代码的功能。有时你甚至能找到警告(例如:"This will crash if the user sents RTL_FOO!!"),没有修复的错误等等东西。一些二进制里有完整的输出函数,例如Dbg_DumpSomeStructure,可以打印出一些大型的数据结构图示,以致于你没必要再进行逆向。调试信息输出也能给你提供有意义的标记名字,常量等。
*断言。微软出色的代码(特别是核心/系统级的)充满了断言。这些断言实际上是C代码,并且常常会给你提供具体的标识名,结构成员或者其他一些未公开的符号的名称。作者以前逆向一个文件时,单纯依靠断言就找到了一个拥有25个成员的结构的其中18个成员的名称(当然还有函数)。
*运行时情况的显示,调试,或者其他有帮助的功能。如果你感到好奇,你实际上能试着在你的系统上使用调试版本(我推荐那些需要被调试的二进制文件/设置)(译注:译者理解为在你的系统上用调试版本的文件替换你需要分析、调试的那些文件)。利用WinDbg对调试文件和调试符号的支持,这个手段能给你提供分析二进制的新方法,创造复杂的调试日志,甚至可以利用内置的消息、时间函数来处理和性能有关的代码。重申一下,只有调试版本能给你提供这些额外的服务。
*跟踪和保护。动态调试发布版本能使你从代码中获得更多信息,但是调试版本能打开内核的很多有利于逆向的调试功能。例如,你能跟踪一个堆的变化,或者内核对象,看见全部的分配和释放、创建和使用它们的地方的列表,这往往比单纯地在一个结构上下内存访问断点有用得多。
那么哪里可以找到它们呢?OSR的站点是一个能经常提供最新链接的站点:050K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3!0K6M7X3!0F1L8r3W2F1k6g2)9J5k6h3y4G2L8g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3X3g2U0k6X3#2Q4x3@1k6A6k6q4)9K6c8o6t1#2z5b7`.`.
2)PDBs(符号)
或许我本应把这放在最前面,因为它实在太基本了,但根据文章的逻辑顺序,我把它放在这里。PDBs、符号、调试数据库,无论你怎么称呼它,它都是逆向工程的基本元素之一。在大多数的符号文件中,它们能提供给你对应的二进制文件中的每一个函数的名称(除了静态的) ,以及全局变量。即使在OMAP优化的二进制文件中,它们也包含了函数分块的特别信息。这意味着你调用080854处的函数时,调试器会给你转换成AdvapipGenerateHash,使判断起来容易得多。在HAL(硬件加速层)或Kernel(系统内核)中,PDBs也包含了大量的没有在WDK/PSDK中提供的内部结构。IDA不会主动去解析它们,不过你可以使用IDA的pdbPlus(558K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3c8S2N6r3q4J5k6i4y4U0N6h3g2Q4x3X3g2U0L8$3#2Q4x3V1k6A6k6r3q4T1j5i4y4W2i4K6u0r3k6Y4u0W2k6h3k6A6L8r3g2K6i4K6u0r3f1p5c8n7f1r3I4#2M7#2)9J5k6i4A6A6M7q4!0q4c8W2!0n7b7#2)9^5z5g2!0q4y4W2)9^5c8W2)9&6x3W2!0q4y4q4!0n7b7W2!0n7y4W2!0q4y4W2)9&6c8q4!0m8y4g2!0q4z5q4!0m8c8g2!0m8z5f1W2p5b7g2!0q4z5q4)9^5y4#2!0m8b7g2!0q4y4g2)9^5b7g2!0m8z5q4!0q4y4g2)9&6b7#2!0n7x3q4!0q4y4W2!0n7y4#2!0n7b7W2!0q4y4g2)9^5b7g2!0m8x3q4!0q4z5q4!0n7c8W2)9&6z5g2!0q4y4q4!0n7b7g2)9&6b7W2!0q4y4#2!0n7b7W2)9&6x3#2!0q4y4W2)9&6c8g2)9^5y4q4!0q4x3#2)9^5x3q4)9^5x3R3`.`.
3)WinDBG
The Debugging tools for Windows(Windows Debugger/WinDBG),是一件极具价值的工具。不是对于它的反汇编功能,而是对它提供的无数来扩展来说的,甚至还包括内置的函数来打印其他途径没法找到的结构。例如,它有两款扩展能打印出CSR_PROCESS和CSR_THREAD,CSRSS使用的两个结构,这两个结构没有在任何公开的文档中提及。再次,能获得结构体、符号、标识和常量的名称对理解函数做了些什么有很大的帮助。
4)信息
现在你已经准备好了分析的工具和被分析的程序,不过你还有一件事要做:学习、阅读,熟悉你将要调试和逆向的东西。先看看能获得的公开文档,搜索一下Internet站点,看见其它人已经发现了什么。但是在没有弄清fs:18h(TEB.NT_TIB.Self)代表了什么,在TEB块的874h处的结构体成员是什么,以及在那里0x5标识了什么的时候,请不要发布类似"我操,把fs:18h里的地址加上874h偏移量的那个地址里的值和5做与运算以后再右移3位,然后就出错了"。因为你不过发现了设置NtCurrentTeb()->CrashMode & PS_CRASH_IMMEDIATELY会导致出错提示,没啥意思的。如果一定要说的话,至少把那些结构体的名字放上去,免得让人看得一头雾水。
友情提示:
5)代码质量
避免发布浪费他人时间的废话,比如刚才那个例子,这里给出一些建议:
*给你的代码加上正确、详细的注释。
如果我看见一些表述新发现的文章,但是没有多少注释,我不会认为你是懒惰的,因为你花了很多时间来逆向它;相反我会认为你并没有清楚地搞懂你的代码做了些什么,为什么这么做。
*可移植性。
更常见的是,底层的NT代码是不可移植的。虽然这往往是设计的原因,但是试着尽量保持可移植性也没有什么坏处。不要通过直接使用sysenter来进行系统调用跳入Ring0。没错,这样做的话,只需要2个时钟周期,你看起来很酷;不过很遗憾这样做没法在我打过SP补丁的系统上工作。还有,不要用硬编码的偏移量。尽量使用头文件或者内嵌结构体定义,这样,如果这些定义在不同系统上有版本区别的话我可以通过NTDDI_VERSION来创建我需要运行的兼容版本。
*线程安全,多处理器支持。
再次地,很多底层的NT代码好像在说"oh well, I'm hacking sh*t anyways, who cares if I do it badly and I don't respect actual coding methdology".在你发布你的代码之前,尽量在多种系统上测试它。尝试在不同的复杂运行环境下运行它,判断潜在的冲突并修复它们,保证你的代码是线程安全以及多处理器兼容的。你自己使用单处理器的电脑不代表别人使用的电脑也是单处理器的。在多处理器系统上有很多NT内核模式的问题是单处理器系统上不需要考虑的,始在NT 核心态里担心什么时候你在一台多处理器的机器上。在需要的时候在C语言里使用“volatile”。(volatile是用来修饰变量的,表明某个变量的值可能在外部被改变,因此对这些变量的存取不能缓存到寄存器,每次使用时需要重新存取。该关键字在多线程环境下经常使用,因为在编写多线程的程序时,同一个变量可能被多个线程修改,而程序通过该变量同步各个线程) 有必要就使用互缩的操作。不要改变能同时被另外一个线程读取的指针。不要在没有同步所有的CPU之前做CPU层次的修改(去看看IPI吧)。每个CPU都有它自己的IDT,GDT等等东西。在你只hook一个CPU之前记住这一点。
*64位系统
还有,不要因为你只有32位的电脑而不去对程序做64位系统的兼容性考量。当然,有时那很困难,不过至少你可以使用/Wp64来得知一些明显的64位不兼容代码。如果可能的话,尽可能少用汇编代码。新版本的MSC(在WDK或者MSVC 2005里,版本14)有很多支持可移植性的新特性,包括很多类似获得返回地址,读取eflags寄存器,设置、读取、写入各种寄存器比如fs、gs、dr*、cr*等等的功能,可以善加利用。
这是我现在能想起的全部,并且我希望我所说的话没有使人不愉快。我所有给出的例子是我所想象出来的常见的情况,并没有特别针对任何人,请勿多虑。
来自913K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3!0H3k6h3&6J5j5$3g2Q4x3X3g2G2M7X3N6Q4x3V1k6T1L8r3!0Y4i4K6u0r3N6X3W2W2N6#2)9J5c8U0t1&6x3R3`.`.
作者:AlexIonescu
作者是reactos 的内核开发者,AlexIonescu 自己还有一个主页在0c6K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3q4D9k6i4S2Q4x3X3c8A6L8$3&6W2M7$3y4#2i4K6u0W2j5$3!0E0i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1&6i4K6R3%4i4K6S2o6i4@1f1&6i4K6W2p5i4@1p5J5i4@1f1@1i4@1t1&6i4K6W2r3i4@1f1&6i4K6R3K6i4@1u0p5i4@1f1#2i4@1p5@1i4@1p5%4i4@1f1&6i4K6R3%4i4K6S2r3i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1#2i4@1p5#2i4@1u0p5i4@1f1@1i4@1t1^5i4K6W2o6i4@1f1^5i4@1p5#2i4@1u0r3i4@1f1K6i4K6R3H3i4K6R3J5i4@1f1@1i4@1u0n7i4K6V1$3i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1#2i4K6R3#2i4@1t1%4i4@1f1@1i4@1u0p5i4K6V1K6i4@1f1@1i4@1u0n7i4K6S2n7i4@1f1%4i4@1u0n7i4K6S2p5i4@1f1K6i4K6R3H3i4K6R3J5
5bcK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8X3u0D9L8$3N6K6i4K6u0r3j5h3c8$3k6r3u0Y4i4K6g2X3M7%4W2K6N6r3g2E0i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5J5y4U0S2Q4x3X3g2S2M7%4m8^5
da3K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8X3u0D9L8$3N6K6i4K6u0r3j5h3c8$3k6r3u0Y4i4K6g2X3M7%4W2K6N6r3g2E0i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5K6y4U0W2Q4x3X3g2S2M7%4m8^5
9e5K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8W2!0q4y4q4!0n7z5g2)9&6c8W2!0q4y4W2)9&6z5q4!0m8c8W2!0q4y4q4!0n7z5q4!0m8b7g2!0q4y4q4!0n7z5q4)9^5c8q4!0q4z5g2)9&6y4q4)9&6z5g2!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4#2!0n7c8q4)9&6x3g2!0q4y4#2!0m8b7W2)9&6z5g2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4W2!0n7y4#2!0n7x3g2!0q4y4g2)9^5y4g2!0m8y4g2!0q4y4#2!0m8x3q4)9&6y4q4!0q4y4#2!0m8z5g2!0n7y4W2N6A6L8X3c8G2N6%4y4Q4c8e0g2Q4z5o6k6Q4z5o6g2Q4c8e0W2Q4z5o6y4Q4b7e0S2Q4c8e0g2Q4z5p5g2Q4z5f1k6Q4c8e0N6Q4z5e0m8Q4z5o6k6Q4c8e0N6Q4b7U0y4Q4b7V1u0Q4c8e0g2Q4z5o6S2Q4z5e0N6Q4c8e0S2Q4b7f1k6Q4b7V1g2Q4c8e0N6Q4b7e0S2Q4z5p5u0Q4c8e0N6Q4b7U0y4Q4b7V1u0Q4c8e0g2Q4z5o6S2Q4z5e0N6Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8e0k6Q4z5f1y4Q4z5o6W2Q4c8e0g2Q4z5o6N6Q4b7e0m8Q4c8e0S2Q4b7f1g2Q4b7U0u0Q4c8e0k6Q4z5e0S2Q4b7f1k6Q4c8e0N6Q4b7V1c8Q4z5e0q4Q4c8e0N6Q4b7f1u0Q4z5e0W2Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0N6Q4b7V1u0Q4b7U0c8Q4c8e0k6Q4z5p5q4Q4b7e0c8Q4c8e0S2Q4z5o6m8Q4z5o6g2Q4c8e0S2Q4b7f1g2Q4b7U0u0Q4c8e0N6Q4z5f1q4Q4z5o6b7`.
我觉得我应该在博客一开始就把这些小贴士放上……其中一些看起来是显而易见的,但是我发现很多逆向工程师并没有意识到这些会对NT系统的逆向和调试提供很大的方便。随意给我发送何额外的资源以便我能加上它们。
1)调试版本(Checked Builds)。
你得首先准备好它。如果你正在逆向一个发行版的二进制文件,请立即停下吧。你已经错过了大量的调试信息,断言和更容易读懂的代码。这里列举一些调试版本的优势:
*大多数情况下NT系统的调试版本都是免费。那是正确的,如果你想要比较不同版本的NT系统之间的区别,你不需要带上每个发行版本的CD(或者更遭,在因特网上面寻找)。NT Service Packs 包含所有你想逆向的系统内核文件,而且包括调试版本在内的NT Service Packs也是可以免费地下载的。现在,你可以免费地对Windows2003的二进制文件进行逆向了。
*读起来的容易得多的代码。调试版本编译的时候不会使用编译器的OMAP技术,OMAP技术会在编译的时候吧函数分割为不同的块并重新编排它们以方便CPU缓存它们。那意味着函数可以被线性和轻松地被逆向。
*调试信息输出。这个是很棒的东西。M$开发者正告诉你在他们的代码里发生着什么,因此你不必猜测这些代码的功能。有时你甚至能找到警告(例如:"This will crash if the user sents RTL_FOO!!"),没有修复的错误等等东西。一些二进制里有完整的输出函数,例如Dbg_DumpSomeStructure,可以打印出一些大型的数据结构图示,以致于你没必要再进行逆向。调试信息输出也能给你提供有意义的标记名字,常量等。
*断言。微软出色的代码(特别是核心/系统级的)充满了断言。这些断言实际上是C代码,并且常常会给你提供具体的标识名,结构成员或者其他一些未公开的符号的名称。作者以前逆向一个文件时,单纯依靠断言就找到了一个拥有25个成员的结构的其中18个成员的名称(当然还有函数)。
*运行时情况的显示,调试,或者其他有帮助的功能。如果你感到好奇,你实际上能试着在你的系统上使用调试版本(我推荐那些需要被调试的二进制文件/设置)(译注:译者理解为在你的系统上用调试版本的文件替换你需要分析、调试的那些文件)。利用WinDbg对调试文件和调试符号的支持,这个手段能给你提供分析二进制的新方法,创造复杂的调试日志,甚至可以利用内置的消息、时间函数来处理和性能有关的代码。重申一下,只有调试版本能给你提供这些额外的服务。
*跟踪和保护。动态调试发布版本能使你从代码中获得更多信息,但是调试版本能打开内核的很多有利于逆向的调试功能。例如,你能跟踪一个堆的变化,或者内核对象,看见全部的分配和释放、创建和使用它们的地方的列表,这往往比单纯地在一个结构上下内存访问断点有用得多。
那么哪里可以找到它们呢?OSR的站点是一个能经常提供最新链接的站点:050K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3!0K6M7X3!0F1L8r3W2F1k6g2)9J5k6h3y4G2L8g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3X3g2U0k6X3#2Q4x3@1k6A6k6q4)9K6c8o6t1#2z5b7`.`.
2)PDBs(符号)
或许我本应把这放在最前面,因为它实在太基本了,但根据文章的逻辑顺序,我把它放在这里。PDBs、符号、调试数据库,无论你怎么称呼它,它都是逆向工程的基本元素之一。在大多数的符号文件中,它们能提供给你对应的二进制文件中的每一个函数的名称(除了静态的) ,以及全局变量。即使在OMAP优化的二进制文件中,它们也包含了函数分块的特别信息。这意味着你调用080854处的函数时,调试器会给你转换成AdvapipGenerateHash,使判断起来容易得多。在HAL(硬件加速层)或Kernel(系统内核)中,PDBs也包含了大量的没有在WDK/PSDK中提供的内部结构。IDA不会主动去解析它们,不过你可以使用IDA的pdbPlus(558K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3c8S2N6r3q4J5k6i4y4U0N6h3g2Q4x3X3g2U0L8$3#2Q4x3V1k6A6k6r3q4T1j5i4y4W2i4K6u0r3k6Y4u0W2k6h3k6A6L8r3g2K6i4K6u0r3f1p5c8n7f1r3I4#2M7#2)9J5k6i4A6A6M7q4!0q4c8W2!0n7b7#2)9^5z5g2!0q4y4W2)9^5c8W2)9&6x3W2!0q4y4q4!0n7b7W2!0n7y4W2!0q4y4W2)9&6c8q4!0m8y4g2!0q4z5q4!0m8c8g2!0m8z5f1W2p5b7g2!0q4z5q4)9^5y4#2!0m8b7g2!0q4y4g2)9^5b7g2!0m8z5q4!0q4y4g2)9&6b7#2!0n7x3q4!0q4y4W2!0n7y4#2!0n7b7W2!0q4y4g2)9^5b7g2!0m8x3q4!0q4z5q4!0n7c8W2)9&6z5g2!0q4y4q4!0n7b7g2)9&6b7W2!0q4y4#2!0n7b7W2)9&6x3#2!0q4y4W2)9&6c8g2)9^5y4q4!0q4x3#2)9^5x3q4)9^5x3R3`.`.
3)WinDBG
The Debugging tools for Windows(Windows Debugger/WinDBG),是一件极具价值的工具。不是对于它的反汇编功能,而是对它提供的无数来扩展来说的,甚至还包括内置的函数来打印其他途径没法找到的结构。例如,它有两款扩展能打印出CSR_PROCESS和CSR_THREAD,CSRSS使用的两个结构,这两个结构没有在任何公开的文档中提及。再次,能获得结构体、符号、标识和常量的名称对理解函数做了些什么有很大的帮助。
4)信息
现在你已经准备好了分析的工具和被分析的程序,不过你还有一件事要做:学习、阅读,熟悉你将要调试和逆向的东西。先看看能获得的公开文档,搜索一下Internet站点,看见其它人已经发现了什么。但是在没有弄清fs:18h(TEB.NT_TIB.Self)代表了什么,在TEB块的874h处的结构体成员是什么,以及在那里0x5标识了什么的时候,请不要发布类似"我操,把fs:18h里的地址加上874h偏移量的那个地址里的值和5做与运算以后再右移3位,然后就出错了"。因为你不过发现了设置NtCurrentTeb()->CrashMode & PS_CRASH_IMMEDIATELY会导致出错提示,没啥意思的。如果一定要说的话,至少把那些结构体的名字放上去,免得让人看得一头雾水。
友情提示:
5)代码质量
避免发布浪费他人时间的废话,比如刚才那个例子,这里给出一些建议:
*给你的代码加上正确、详细的注释。
如果我看见一些表述新发现的文章,但是没有多少注释,我不会认为你是懒惰的,因为你花了很多时间来逆向它;相反我会认为你并没有清楚地搞懂你的代码做了些什么,为什么这么做。
*可移植性。
更常见的是,底层的NT代码是不可移植的。虽然这往往是设计的原因,但是试着尽量保持可移植性也没有什么坏处。不要通过直接使用sysenter来进行系统调用跳入Ring0。没错,这样做的话,只需要2个时钟周期,你看起来很酷;不过很遗憾这样做没法在我打过SP补丁的系统上工作。还有,不要用硬编码的偏移量。尽量使用头文件或者内嵌结构体定义,这样,如果这些定义在不同系统上有版本区别的话我可以通过NTDDI_VERSION来创建我需要运行的兼容版本。
*线程安全,多处理器支持。
再次地,很多底层的NT代码好像在说"oh well, I'm hacking sh*t anyways, who cares if I do it badly and I don't respect actual coding methdology".在你发布你的代码之前,尽量在多种系统上测试它。尝试在不同的复杂运行环境下运行它,判断潜在的冲突并修复它们,保证你的代码是线程安全以及多处理器兼容的。你自己使用单处理器的电脑不代表别人使用的电脑也是单处理器的。在多处理器系统上有很多NT内核模式的问题是单处理器系统上不需要考虑的,始在NT 核心态里担心什么时候你在一台多处理器的机器上。在需要的时候在C语言里使用“volatile”。(volatile是用来修饰变量的,表明某个变量的值可能在外部被改变,因此对这些变量的存取不能缓存到寄存器,每次使用时需要重新存取。该关键字在多线程环境下经常使用,因为在编写多线程的程序时,同一个变量可能被多个线程修改,而程序通过该变量同步各个线程) 有必要就使用互缩的操作。不要改变能同时被另外一个线程读取的指针。不要在没有同步所有的CPU之前做CPU层次的修改(去看看IPI吧)。每个CPU都有它自己的IDT,GDT等等东西。在你只hook一个CPU之前记住这一点。
*64位系统
还有,不要因为你只有32位的电脑而不去对程序做64位系统的兼容性考量。当然,有时那很困难,不过至少你可以使用/Wp64来得知一些明显的64位不兼容代码。如果可能的话,尽可能少用汇编代码。新版本的MSC(在WDK或者MSVC 2005里,版本14)有很多支持可移植性的新特性,包括很多类似获得返回地址,读取eflags寄存器,设置、读取、写入各种寄存器比如fs、gs、dr*、cr*等等的功能,可以善加利用。
这是我现在能想起的全部,并且我希望我所说的话没有使人不愉快。我所有给出的例子是我所想象出来的常见的情况,并没有特别针对任何人,请勿多虑。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
赞赏
雪币:
留言: