第10页13行: "这时,ESP指向栈项" 应该为 "栈顶" (老大用五笔?:))
第12页图2.3: "Low Memory Addresses and Bottom of Stack" 应该为 "High Memory Address and Bottom of Stack"
"High Memory Addresses and Top of Stack" 应该为 "Low Memory Addresses and Top of Stack"
根据"array是5个字节"(第13页倒数第7行), 判断第11页的 int array[5] 是否应该为 char(或u_int8_t)类型?
第30页10行:在正常情况下,每个系统调用支持6个参数,分别保存在EBX,ECX,EDX,ESI,EDI和EPB里。
英文原文是:Each syscall can have a maximum of six arguments, which are inserted into EBX, ECX, EDX, ESI, EDI, and EPB, respectively.
第50页第5段(这个结果虽然出乎我们的意料,……)
第2行:……,我们刚刚输入的字符串中的4个字符被当作“数字”传递给printf函数,……
英文原文是:……,so 4-byte segments from the string are being passed as the "numbers" to be substituted into the string.
按照我的理解,原文的意思应该是:我们刚刚输入的字符串每4个字符被当作1个“数字”传递给printf函数
也就是说,字符串被分成每4个字符一段,分别作为格式化参数传递给了printf函数。而译文给人的感觉是:我们刚刚输入的字符串中“只有”4个字符被当作“数字”传递给printf函数,给人产生了误解和歧义。
第62页第2段(注意标为粗体的那行。)
那里比较有意思,在错误的调用vsnprintf之后,程序的作者争取的调用了printf。
原文是:The interesting point is that there's a call to printf right after the vulnerable call to vsnprintf.
最后谈点小意见,这章的最后一句是:that they are worth understanding.
愚以为,对基本原理的理解,应该胜过简单的掌握和熟练现成的技巧。理解了原理,加上我们充满灵感的想象力,就可以搞出无数令人称奇的新技巧。软件每时每刻都在更新,不可能有一劳永逸的现成的技巧,所以,“理解(原理,规律)”,活的理解(ing),可能比“学”“习”(现成的技巧)更重要。
第72页第1段第1行
译文:本章主要介绍Linux上的堆溢出,使用的堆实现源自Doug Lee最初的malloc实现,……
原文:This chapter focuses on heap overflows on the Linux platform, which uses a malloc implementation originally written by Doug Lee,……
注:不好意思,第一行就找您的岔。原文中的which应该指代的是“堆溢出”(heap overflows),“使用的堆实现”似乎有些不合适,因为堆的实现在这里暂时还看不出和主题什么关系。也许改为:……,利用了源自Doug Lee最初的malloc实现,…… 较妥。不知arhat大哥意下如何。
第72页第2段第4行
译文:一个典型的Linux程序通常包括.bss段(为初始化的全局变量),用brk()或mmap()分配的、由malloc()使用的.data段(已初始化的全局变量)。
原文:Typically a Linux program has a .bss (global variables that are uninitialized) and a .data segment (global variables that are initialized) along with other segments used by malloc() and allocated with the brk() or mmap() system calls.
注:这个问题就比较严重了,必须要纠正,技术上是不能有这样的概念错误的:.data段当然不是用brk()或mmap()分配的、由malloc()使用的,.data段就只是用来存放已初始化的全局变量的。从原文中也可以看出“along with other segments used by……”。
愚以为,应翻译成:一个典型的Linux程序通常包括.bss段(为初始化的全局变量),.data段(已初始化的全局变量)和其他的用brk()或mmap()等系统调用分配的、由malloc()使用的一些段。总之概念上决不能有混淆,希望arhat大哥在这个基本概念的基础上对这句话做出语言上更准确地翻译。
arhat:汗!这个是我理解上的错误
第77页第1行
译文:……,并把buf2块头部的0xfffffff0改为0xffffffff。
原文:…… and changing the chunk header of buf2 to have a size of 0xfffffff0 and a previous size of 0xffffffff.
注:原文的意思是:修改buf2块的头部,使得buf2块的大小变成0xfffffff0,buf2块的前一块的大小变成0xffffffff。其实就是把buf2块头部的8个字节分别修改成0xffffffff,0xfffffff0。因为buf2块头部的8个字节分别存储的是buf2块的前一块的大小(32位)和buf2块的大小(32位)。从下面的这条命令本身也可以看出:
(gdb) run `python -c 'print
"A"*1024+"\xff\xff\xff\xff"+"\xf0\xff\xff\xff"'`
第77页第5段第3行
译文:那你应该注意,在大多数情况下,free()是infree的封装;……
原文:…… you should note that free() is really a wrapper to intfree in most cases.
注:笔误,将intfree写成了infree,少了一个n。
第78页第1,2段
译文:
在第一条指令(mov 0x8(%esi), %edx)里,……
在第二条指令(add %eax, %edi)里,……
原文:
In the first instruction (mov 0x8(%esi), %edx), ……
In the second instruction (add %eax, %edi), ……
注:arhat大哥的翻译和原文内容一致,可惜原文内容写错了。稍微阅读下这两段,就会发现,这两条指令本应该是这两段上面的那两条指令,可惜被误写为这两段下面的那五条指令的前两条,完全对不上号。
故,原文应为:
In the first instruction (mov 0xfffffff8(%edx),%eax), ……
In the second instruction (sub %eax,%esi), ……
译文也应相应作出修改。
第78页第4段第1行
译文:……,接着用前一个块的大小减去4改写buf2的块头部;……
原文:……, then overwrite the chunk header of buf2 with a previous size of -4. ……
注:arhat大哥理解错作者的意思了,其实作者是说用-4(补码0xfffffffc)填充buf2的块头部的前4个字节,也就是存储前一个块的大小的那32位。从下面的这条命令本身可以看出来:
(gdb) r `python -c 'print
"A"*(1024)+"\xfc\xff\xff\xff"+"\xf0\xff\xff\xff"+"AAAAABCDEFGH" '`
第79页最后一行
译文:我们正好可以把word1和栈上的地址作为word2。
原文:We can just use that as word1 and an address on the stack as word2.
注:根据上下文,我推断,作者这里的意思是说把exit函数指针(that所指代的)的地址作为word1(其实实际应该是word1+12),而栈上的某个地址(当然是某个shellcode的首地址啦)作为word2。因为word2会写入word1+12,所以改写了本来指向exit函数的函数指针,使得对exit函数的调用变成了对栈上word2地址处的跳转。不知arhat大哥意下如何。
第六章 Windows的广阔原野
第90页第3段第1行
译文:……,在1991年首次发行了Windows 3.1。……
原文:……, with its first release in 1991 as Windows NT 3.1 .……
注:Windows 3.1和Windows NT 3.1还是不同的,其实在XP以前,Windows系列和Windows NT一直是Microsoft的两条主线,两者有不同的内核,面向不同的对象。比如Windows 3.1不是一个独立的操作系统,必须在DOS下进行加载,很像现在Linux下的XWindow。而Windows NT 3.1从一开始就立足于全新的内核,是一个独立的操作系统。
Windows NT 3.1到Windows NT 4.x到Windows NT 5.0(Windows 2000)
Windows 3.x到Windows 9x到Windows Me
最后两个系列合并成了Windows XP,后来又有了Windows 2003及现在的Windows Vista
很小的时候就在DOS上接触了Windows 3.1(在命令行下输入win加回车,呵呵),作为Windows发展历史的见证人,关于这个问题我还是有发言权的,呵呵。
arhat:是我的笔误 :)
第95页第5段第2行
译文:……和Todd Sabin的DCE-RPC(http://razor.bindview.com/)。
原文:…… and Todd Sabin's DCE-RPC tools (available from http://razor.bindview.com/).
注:DCE-RPC当然不是Todd Sabin的啦,arhat大哥这里少翻译了一个“tools”,其实应该是:“Todd Sabin的DCE-RPC工具包”。或者直接就是“Todd Sabin的DCE-RPC tools”。
第100页第4段第1行
译文:……,大部分是由未公开的,……
原文:……, and many of these are undocumented ……
注:根据上下文,我认为译文中多打了一个“由”字,本来应该是:“大部分是未公开的”。而且如果不去掉这个“由”字,则译文有些文法不通。
arhat:YES
第100页第4段第2行
译文:例如,加载LibraryA()时(把DLL载入内存),……
原文:For example, Load_LibraryA(), which loads a DLL into memory,……
注:这个API我用过,所以我有发言权,这个函数应该是LoadLibraryA(),在MSDN里面查不到这个函数的,顶多查到LoadLibrary(),其实LoadLibrary()是定义在windows.h里面的一个宏,其实大家也应该想到了,还有另一个函数,就是LoadLibraryW()。LoadLibraryA()和LoadLibraryW()的区别就在于接受dll路径及文件名作为参数时,一个把参数处理成ASC单字符,一个处理成宽字符。这些MSDN里面一点都没有提到。我之所以用到LoadLibraryA()这个函数(一般肯定就用LoadLibrary()了),是因为那时搞远程DLL注入,就是利用CreateRemoteThread()在远程进程内创建线程,线程的功能就是载入DLL,当然线程函数就要用LoadLibrary(),可是LoadLibrary()其实根本就是个宏,根本不可能在kernel32.dll中GetProcAddress(),所以必须用LoadLibraryA()或LoadLibraryW()。
不好意思说多了,其实原文也有误导,偏偏在一个完整的函数中间加一个“_”(注:要是在Windows里面真的调用Load_LibraryA(),是绝对调不成功的,而且Win32API是绝不可能在函数名里面有个“_”的),结果也误导了arhat大哥。其实文章后面很快就讲到了DLL注入类似的内容,而且也正确地书写了LoadLibraryA()(这次arhat大哥当然翻译得就没错啦)。
arhat:very good
第101页第6段第1行
译文:WSASicjet(),调用WSASicjet()而不是……
原文:WSASocket() Calling WSASocket() instead of ……
注:明显的笔误,在译文里这个函数怎么看怎么不对劲怎么又似曾相识。WSASocket()这个函数我也用过,当时看来相比socket()的优势就是可以交叠处理提高效率。