|
|
February 22 以前一直在FireFox下面显示不正常,刚才去更新的LiveWriter的时候发现LiveWriter的Blog正常显示了,当时就在想,是不是因为LiveWriter的Theme可以正常显示,而我选择的不可以,没想到浏览偶的Blog居然也可以正常显示了...HOHO... December 27 Debugging/Reversing NT System Binaries 来自http://www.openrce.org/blog/view/292 作者:AlexIonescu 作者是reactos 的内核开发者,AlexIonescu 自己还有一个主页在http://www.alex-ionescu.com,里面也都大量的好东西。他的具体介绍。 http://advdbg.org/blogs/advdbg_system/articles/268.aspx http://advdbg.org/blogs/advdbg_system/articles/369.aspx http://advdbg.org/也是个不错的网站,深入研究Windows内部原理系列课程系列中有几讲是网站的维护者讲的 我觉得我应该在博客一开始就把这些要点放上……其中一些看起来是显而易见的,但是我发现很多逆向工程师并没有意识到这些会对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的站点是一个能经常提供最新链接的站点:http://www.osronline.com/article.cfm?id=259 2)PDBs(符号) 或许我本应把这放在最前面,因为它实在太基本了,但根据文章的逻辑顺序,我把它放在这里。PDBs、符号、调试数据库,无论你怎么称呼它,它都是逆向工程的基本元素之一。在大多数的符号文件中,它们能提供给你对应的二进制文件中的每一个函数的名称(除了静态的) ,以及全局变量。即使在OMAP优化的二进制文件中,它们也包含了函数分块的特别信息。这意味着你调用080854处的函数时,调试器会给你转换成 AdvapipGenerateHash,使判断起来容易得多。在HAL(硬件加速层)或Kernel(系统内核)中,PDBs也包含了大量的没有在 WDK/PSDK中提供的内部结构。IDA不会主动去解析它们,不过你可以使用IDA的pdbPlus(http://www.datarescue.com/idabase/freefiles/PDBPlus.zip)插件来让IDA自动地添加这些结构。 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*等等的功能,可以善加利用。 这是我现在能想起的全部,并且我希望我所说的话没有使人不愉快。我所有给出的例子是我所想象出来的常见的情况,并没有特别针对任何人,请勿多虑。 ======================================================================================= 来自http://www.openrce.org/blog/view/292 作者:AlexIonescu 作者是reactos 的内核开发者,AlexIonescu 自己还有一个主页在http://www.alex-ionescu.com,里面也都大量的好东西。他的具体介绍。 http://advdbg.org/blogs/advdbg_system/articles/268.aspx http://advdbg.org/blogs/advdbg_system/articles/369.aspx http://advdbg.org/也是个不错的网站,深入研究Windows内部原理系列课程系列中有几讲是网站的维护者讲的 Here are some tips I thought I'd share in an blog entry... some of these may seem fairly obvious, but I've come across many reverse engineers who are not aware of the wealth of resources available for easier NT reversing and debugging. Feel free to message me any additional resources so that I may add them. 1) Checked builds. This is your first priority. If you are reversing a retail binary, STOP NOW. You are missing out on a wealth of debugging messages, assertions and easier to read code. Here are some of the advantages of checked builds: * Mostly FREE for ANY NT OS. That's right, if you want to compare code across NT versions, you don't need to carry your 15 CDs of every version released (or worse, beg around the Internet). NT Service Packs contain all the core system files you're likely to reverse, and their checked builds are free to download. Granted, you will be missing out on the retail versions, but now you don't need to buy Windows 2003 to reverse a Windows 2003 binary. * Much, much, much easier code to read. Checked builds are not built with OMAP, the compiler technology which splits up functions in chunks and re-organizes them for better CPU caching. That means that functions are linear and a breeze to reverse. * Debug prints. These are just awesome. Microosft developers are telling you what's going on in their code, so you don't have to guess. Sometimes you can even find warnings (ie: "This will crash if the user sents RTL_FOO!!"), unfixed bugs, etc. Some binaries have entire built-in dumping functions, such as Dbg_DumpSomeStructure, which will graphically print out some huge structure that you don't need to reverse anymore. Debug prints can also give you valuable flag names, constants and etc. * Assertions. Good Microsoft code (especially core/system-level) is filled with assertions. These assertions are actually C code, and more often then not will give you the name of a flag, structure member, or other symbolic names which are not public. While reversing a file once, I was able to find the name (and thus function) of about 18 fields out of a 25 field structure, merely by reading the assertions. * Run-time profiling, debugging, or other helpful functions. If you are feeling curious, you can actually try using a checked build live on your system (I recommend only the specific binary/set, however). Coupled with WinDBG, this could give you new ways to analyze the binary, create complex debug logs, and even use built-in profiling/timing code if your reversing project is performance related, or if you're just curious. Again, only in a checked build. * Tracing and protection. This applies more for testing your code, but checked builds also enable many tracing options in the kernel, which can be useful for reversing. For example, you can track a heap block, or any kernel object, and see a list of all acquires/releases, creators and users, which can sometimes be more useful then putting a memory breakpoint on a structure. OK, so where to get them? A good place for up-to-date links is on OSR's site: http://www.osronline.com/article.cfm?id=259 2) PDBs (Symbols). Perhaps I should've put this first, because it really is even more basic, but I'm going at this in logical order. PDBs. Symbols. Debug Databases. Whatever you want to call them, you should not be reversing without them. In their most basic form, they will give you the internal name of every function in your binary (except statics), as well as global variables. With an OMAP-binary, they also contain special information to link chunked functions together. This means that your call 080854 just became call AdvapipGenerateHash, making your job a lot easier. With something like HAL or the kernel, PDBs also contain a wealth of structures not publically documneted in the WDK/PSDK. IDA doesn't unfortunately parse them, but if you use the pdbPlus plugin (available on the site), IDA will automatically add them to its structure database. 3. WinDBG. The Debugging tools for Windows (Windows Debugger/WinDBG) is an extremly valuable tool, not for its diassembler, but for the myriad of extensions that it provides, which also have built-in code to dump structures which are unavaialble anywhere else. For example, two of its extensions are able to dump CSR_PROCESS and CSR_THREAD, which are the structures used by CSRSS, and not documented anywhere. Again, having access to structures and symbolic/flag/constant names can go a long way toward understanding what a function does. 4. Information Now that you're all setup with the tools and binary, there is one more thing you should do: learn, read, and get acquainted with what you're going to debug/reverse. Read all the documentation avaialble, browse internet sites, see what others have discovered. But please don't post excitely that "omfg, if you set fs:18h+874h & 0x5 >> 3 you get a bugcheck", when you haven't taken the time to understand what fs:18h is in the first place, what member of the TEB 874h is, and what the 0x5 flag's symbolic name/meaning is. Because you might as well have discovered that setting NtCurrentTeb()->CrashMode & PS_CRASH_IMMEDIATELY crashes, which isn't really interesting to know, or at the very least, makes a lot more sense if presented that way. Bonus: 5. Code Quality Apart from avoiding to produce un-symbolized crap like seen above, it's a good idea to: * Comment your code. Properly. Extensively. If I see some discovery or exploit that is poorly commented, I'm not going to assume you were lazy, since you spent all this time reversing it, I'm going to assume you don't really know why your code is doing what it's doing. * Portability. More often then not, low-level NT code is completely unportable. While this is by design in many cases, it wouldn't hurt to try remaining as compatible as possible. Don't do systemcalls by using sysenter directly. Yes, yes, you look cool and it's 2 cycles faster, but it'll also not run on my service pack. And again, don't hard-code offsets. Use actual structures/headers, which may be versionned so that if I want a compatible version on 2003, I can just build it by using NTDDI_VERSION. * Thread safety, multi-processor. Again, much low-level NT code seems to be saying "oh well, I'm hacking sh*t anyways, who cares if I do it badly and I don't respect actual coding methdology". Before you publish your code, try to test it on a variety of systems. Try to profile it and stress it. Identify potential race conditions and fix them. Make sure your code is thread-safe and multiprocessor compatible. Just because you're running on an uni-processor machine doest't mean everyone else is. There a are a great number of things you need to start worrying about in NT kernel mode when you're on a multi-processor machine. Use "volatile" in C when needed. Use Interlocked operations when required. Don't change a pointer that could be read by another thread in the same time. Don't do CPU-level modifications without synchronizing them to both CPUs (learn about IPI). Each CPU has its own IDT, GDT, etc. Remember that before you only hook one. * 64-bit Again, just because you don't have a 32-bit machine doesn't mean you don't have to make your code as compatible on 64-bit as possible. Sure, that's sometimes impossible, but at least use /Wp64 so you get warned about obvious 64-bit incompatibilities and broken code. Minimize your use of assembly if possible. Version1 14 of MSC (in the WDK or MSVC 2005) has many intrinsics that are portable when recompiled, including stuff like getting the return address, reading eflags, setting/reading/writng fs/gs/dr*/cr*, etc. That's all I can think of for the moment, and I hope nobody takes this offensively. All the examples I've given were out of my head and I'm not targetting anyone in particular, these are just some considerations. December 25 以下内容摘自<Windows核心编程>: DWORD FuncaDoodleDoo() { DWORD dwTemp = 0; // (1) while (dwTemp < 10) // (2) { __try // (3) { if (dwTemp == 2) // (4) { continue; // (5) } if (dwTemp == 3) // (6) { break; // (7) } } __finally // (8) { dwTemp++; // (9) } dwTemp++; // (10) } dwTemp += 10; // (11) return(dwTemp); // (12) } 通过给上述代码添加的编号, 看一下上面代码的执行流程. 第一次循环: (1)初始化dwTemp为0. (2)进入循环. (3)进入__try块 (4)和(6)都为FALSE (8)进入__finally, dwTemp递增 (10)dwTemp再次递增. 经过第一次循环后, dwTemp的当前值为2 第二次循环: (4)条件为TRUE. (注:如果没有__try块, 那么这段代码将是无限循环) 因为使用了__try, 系统知道continue将 过早的退出__try, 而执行__finally. (8)进入__finally, dwTemp递增. 但__finally块后的代码不执行, 又返回到continue, 继续执行循环. 经过第二次循环后, dwTemp的当前值为3 第三次循环: (4)条件为FALSE; 继续执行. (6)条件为TRUE. 因为使用了__try, 系统知道break将过早的退出__try, 而执行__finally. (8)进入__finally, dwTemp递增, 但__finally块后的代码不执行, 又返回到break, 跳出循环. 经过第三次循环, dwTemp的当前值为4 (11)dwTemp加上10. 所以当dwTemp返回时, 值为14. 从以上的代码不难看出, 当使用__try __finally时, 系统将保证不管__try中执行continue, break甚至是return 都将保证__finally块中的代码被执行到. 另外我们需要注意的是: 尽管__try __finally可以捕捉到__try块过早退出的大多数情况, 但当线程或进程被结束时, 它不能引起__finally块中的代码执行. 当调用ExitThread或ExitProcess时, 将立即结束线程或进程, 而不会执行 __finally块中的任何代码. 另外, 如果由于某个程序调用TerminateThread或TerminateProcess, 线程或进程将结束, __finally块中的代码也不执行.
October 19 URL:http://forums.microsoft.com/china/ShowPost.aspx?PostID=2002536&SiteId=15 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。 其格式一般为: #Pragma Para 其中Para 为参数,下面来看一些常用的参数。 (1)message 参数。 Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗 口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: #Pragma message(“消息文本”) 当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。 当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法 #ifdef _X86 #Pragma message(“_X86 macro activated!”) #endif 当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_ X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了 。 (2)另一个使用得比较多的pragma参数是code_seg。格式如: #pragma code_seg( ["section-name"[,"section-class"] ] ) 它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。 (3)#pragma once (比较常用) 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。 (4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。 有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了 #pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。 (5)#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体 外观的定义。 (6)#pragma warning( disable : 4507 34; once : 4385; error : 164 ) 等价于: #pragma warning(disable:4507 34) // 不显示4507和34号警告信息 #pragma warning(once:4385) // 4385号警告信息仅报告一次 #pragma warning(error:164) // 把164号警告信息作为一个错误。 同时这个pragma warning 也支持如下格式: #pragma warning( push [ ,n ] ) #pragma warning( pop ) 这里n代表一个警告等级(1---4)。 #pragma warning( push )保存所有警告信息的现有的警告状态。 #pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告 等级设定为n。 #pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的 一切改动取消。例如: #pragma warning( push ) #pragma warning( disable : 4705 ) #pragma warning( disable : 4706 ) #pragma warning( disable : 4707 ) //....... #pragma warning( pop ) 在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。 (7)pragma comment(...) 该指令将一个注释记录放入一个对象文件或可执行文件中。 常用的lib关键字,可以帮我们连入一个库文件。 每个编译程序可以用#pragma指令激活或终止该编译程序支持的一些编译功能。例如,对循环优化功能: #pragma loop_opt(on) // 激活 #pragma loop_opt(off) // 终止 有时,程序中会有些函数会使编译器发出你熟知而想忽略的警告,如“Parameter xxx is never used in function xxx”,可以这样: #pragma warn —100 // Turn off the warning message for warning #100 int insert_record(REC *r) { /* function body */ } #pragma warn +100 // Turn the warning message for warning #100 back on 函数会产生一条有唯一特征码100的警告信息,如此可暂时终止该警告。 每个编译器对#pragma的实现不同,在一个编译器中有效在别的编译器中几乎无效。可从编译器的文档中查看。 October 15 前几天看到电视里面教做可乐鸡块, 今天就学着做可乐鸡翅...弄是弄出来了, 一尝, 甜的...呵呵...不适合偶....偶不喜欢甜食.. October 08 摘自:代码大全(第二版) Page:666 - 遵循某种系统化的变更控制手续.
- 成组地处理变更请求. 人们倾向于一有想法就去实现有些较容易的变更. 这种处理变更的方法的问题在于, 那些好的变更可能反而被丢掉了.
在这点似乎深有体会, 虽然没有正式跟哪个团队做过项目, 偶尔自己做些小程序玩玩, 但越到后面, 越觉得这是一个不可能完成的项目了, 因为越后面, 想到越多功能, 做到最后发现, 越来离最开始的设想已经很远了... - 评估每项变更的成本.
- 提防大量的变更请求.
- 成立变更控制委员会或者类似机构.
- 警惕官僚主义, 但也不要害怕官僚主义而排斥有效的变更控制.
October 06 摘自:代码大全(第二版) - 对每一项相关的需求进行测试, 以确保需求都已经被实现. 在需求阶段就计划好这部分的测试用例, 或者至少尽早开始——最好在你开始编写待测试的单元之前。注意对需求里面常见的疏漏进行测试。安全级别、数据存储、安装过程以及系统可靠性等,这些都是测试的绝佳素材,并且常常在需求阶段被忽略。
- 对每一个相关的设计关注点进行测试,以确保设计已经被实现。在设计阶段就计划好这一部分的测试用例,或者尽早开始——在你开始编写待测试子程序或者类的具体代码之前。
- 用基础测试(basis testing)来扩充针对需求和设计的详细测试用例。增加数据流测试(data-flow test),然后补充其他所需的测试用例,以便对代码进行彻底的考验。至少,你应该测试到每一行代码。基础测试和数据流测试将在本章稍后部分讨论。
- 使用一个检查表,其中记录着你在本项目迄今为止所犯的,以及在过去的项目中所犯的错误类型。
另:所需基础测试用例的最少数量可以用下面的简单方法计算: - 对通过子程序的直路,开始的时候记1。(大意就是指从1开始累加)
- 遇到下面的每个关键字或者其等价物时,加1:if、while、repeat、for、and以及or。
- 遇到每一个case语句就加1,如果case语句没有缺省情况,则再加1。
如下面的例子: SomeFunction() { code statement; // 从此处开始计1 for (i = 0; i < Num; i++) { // for语句计2 } if (Error || n < MaxNum) { // if语句计3, or计4 } } 所以以上例子中总共需要4个测试用例。 October 05 接着昨天的来, 昨天在浏览太平洋网站论坛的时候, 突然发现怎么翻来翻去都是第1页. 突然发现有一些异样的地方, 浏览器地址栏的指定当前页的参数越来越长了, 当时就觉得不妥. 后来细心看一下发现, 每次打开链接或输入新网址, 都会有一个空白一闪而过, 此间持续时间非常短, 如果想看到这个空白页的内容, 要不用网络流量监控工具, 要不就要手脚麻利了, 看到的网页源代码就是昨天看到的那个, 再贴一次: <iframe src=http://202.*.*.*/npserver/webform1.aspx? height=0 width=0></iframe> <script type="text/javascript"> var myTranFunc = function () { window.location.target="_self" window.location.href="http://*.*.*.*" }; window.setTimeout("myTranFunc()",800); window.setTimeout("myTranFunc()",2000); </script> 其中红色的那段就是你请求的网址, 只要稍微懂HTML和Javascript的就会知道这段代码的用意. 另外在前面内嵌框架里面的页, 我想应该是DX的一个记录页, 在这个页里面可以说是想干什么就可以干什么. 如:监控你请求的所有网址, 或者对你定向推广告等等! 再后来顺藤摸瓜, 找到了http://www.chinasoar.com.cn/product.html, 这就是DX使用监控产品的介绍. 在网页下面我们可以看到如下内容: 宽带私接、串接监管系统”宽带私接、串接监管系统成功案例 - 网通系统:石家庄网通公司、邯郸网通公司、唐山网通公司、邢台网通公司、廊坊网通公司。
- 电信系统:湖南省11个地市电信公司
- 铁通系统:邯郸铁通、保定铁通、秦皇岛铁通。
我想使用以上名单里ISP的用户, 都会有这样的症状 October 04 摘抄自: Code complete(第二版) 计算子程序中决策点数量: 1. 从1开始,一直往下通过程序 2. 一旦遇到以下关键字, 或者其同类的词, 就加1: if、while、repeat、for、and、or 3. 给case语句中的每一种情况都加1 例子: if (((status = Success) and done) or (not done and (numLines >= maxLines))) then 在这段代码中, 从1算起, 遇到if得2, and得3, or得4, and得5. 加起来, 这段代码里总共包含了5个决策点. 当计算出决策点的数量后, 就可以用得到的数值分析你写的子程序的复杂度了: 0——5 子程序可能还不错 6——10 得想办法简化子程序了 10+ 把子程序的某一部分拆分成另一个子程序并调用它 10个决策点的上限并不是绝对的. 应该把决策点的数量当作一个警示, 该警示说明某个子程序可能需要重新设计. 不要死守这个规则. 一条情况很多的case语句可能会包含超过10个元素. 如果硬拆开它可能就是很愚蠢的, 这取决于该case语句的用途. 每次点击一个链接,都先通过该死的网页跳转。唉!DX你干什么呢~~~~~ 和谐的社会,和谐的国企,和谐的人!! <iframe src=http://202.*.*.*/npserver/webform1.aspx? height=0 width=0></iframe> <script type="text/javascript"> var myTranFunc = function () { window.location.target="_self" window.location.href="http://*.*.*.*" }; window.setTimeout("myTranFunc()",800); window.setTimeout("myTranFunc()",2000); </script> October 03 摘自:代码大全第二版(中文版) 下面是几项用于创建缩写的指导原则。其中一些原则彼此冲突,所以不要试图同时应用所有的原则。 - 使用标准的缩写(列在字典中的那些常见缩写)。
- 去掉所有非前置元音。(computer变成cmptr,screen变成scrn,apple变成appl,integer变成intgr。)
- 去掉虚词and, or, the等。
- 使用每个单词的第一个或前几个字母。
- 统一地在每个单词的第一、第二或者第三个(选择最合适的一个)字母后截断。
- 保留每个单词的第一个和最后一个字母。
- 使用名字中的每一个重要单词,最多不超过三个。
- 去除无用的后缀——ing, ed等。
- 保留每个单节中最引人注意的发音。
- 确保不要改变变量的含义。
- 反复使用上述技术,直到你把每个变量名的长度缩减到了8到20个字符,或者达到你所用的编程语言对变量名的限制字符数。
October 02 这应该是第二次从网上购物了,昨天(现在说了应该是前天了)收到物品看,马上打开一看,晕!是台式机内存条,我在TAOBAO拍下的是笔记本内存条,本来是满心希冀的装上新买的笔记本内存条,爽一把的,没想到事与愿违。。。 我很想去相信那是无心而为之,不过我拍的时候还是9月24日,不是9月30日,应该说不是很急吧,作为一个2005年就注册的老铺主,没想到在这样的情况下,会犯下如此低级的错误。这是一位加了消费者保护计划的双钻铺主,唉!这世道,还能相信什么?眼见为实?到手才是财? 其实这样的事我不是第一次看到了,前几天就亲眼目睹了我哥买回来的墨盒,他拿到包裹打开一看,里面少黑色,用的是黄色代替的。还好他工具多,把多的黄色墨盒抽干,再灌入黑色。看到网上购物真的有很长的路要走啊。。。唉!! 现在寄过来的台式机内存条也寄回去了,不管结果是怎么样的(完全被骗了亦或是只是回寄的邮资),我也认了。。。人心难测啊。。。。其实不管是内存条还是邮资,都不是多大的事,只是心有不甘而以,我难道就比你(TAOBAO上某店铺铺主)蠢?难道注定就要被你骗???不管结果如何,斗争到底!!!! PS:我已经将包裹、包裹里面的物品、当时在虚拟铺里面拍下的网页和回寄的EMS,或是照过相了,或是截过屏了。 September 29 参加了区里举行的第八届大众运动会乒乓球项目,仅得了个第五名。-_-!!! 感受了一次——是骡子是马,拿出来溜溜。呵呵。。。 September 16 这个周末看了<<你丫闭嘴(Tais Toi)>>, 搞笑味十足, 呵呵! 里面的钢蛋真的太搞了, 可每次都 因为他而化险为夷, 而当被关在监狱的时候, 里面的医生对他的结论是此人笨到了极点.... ◆中文片名:你丫闭嘴 ◆英文片名:Tais Toi ◆导 演:弗朗西斯·维贝Francis Veber ◆编 剧:Serge Frydman (idea) Francis Veber ◆主 演:让·雷诺Jean Reno 杰拉德·德帕迪约Gerard Depardieu 蕾诺·瓦莱拉Leonor Varela ◆类 型:Comedy / Crime (more) ◆级 别:France:U / Switzerland:10 (canton of Geneva) / Switzerland:10 (canton of Vaud) / Singapore:PG / Switzerland:12 (canton of the Grisons) ◆国 别:法国 ◆出 品:2003 ◆IMDB链接:http://www.imdb.com/title/tt0310203 September 09 因为转星工作, 上级组织部门决定对远程教育用的电脑进行接收软件和操作系统升级. 用了差不多满满一周的时间, 将130多台电脑进行了软件和硬件升级, -_-!!!, 现在是看到装系统都怕了~~~在这里不得不提的就是Ghost, 写这个软件的人真的是太有才了...哈哈!!!! August 16 今天在打篮球的时候, 一个带球突破, 没想到头跟别人的头撞上了, 估计是我运气比较好, 撞在眉间, 被撞的就没那么幸运了, 撞在眉毛下面一点点, 当时那血啊, 可以用涌来形容....我看完后, 说最起码也要缝个3针以上, 后来他从医院回来, 告诉我缝了4针......怕怕!!!!运动一下嘛, 似乎不用这么拼的...嘿嘿, 可能是今天正好撞上了吧, 打了这么多年球了, 第一次碰上这事...... August 11 在单处理机平台上的一些代码放在多处理器平台并不能运行的很好,因为它不能保证你的代码不被运行在其它处理器上的代码所干扰。一个称为自旋锁(spin lock)的原始对象可以解决这个问题。 自旋锁是一种保护数据结构或代码片段的原始方式,这是为了防止多处理器环境下的失步问题而设计的。当同时执行并运行在提高的IRQL 上的例程同时访问共享数据或资源时,自旋锁用来保护这些共享数据或资源。设计正确的自旋锁的重要性就在于,可以保护共享数据的安全,可以明确相应的中断优先级。内核提供的自旋锁主要有两种:中断自旋锁和执行程序自旋锁, 和它们关联的中断优先级分别为: DIRQL 和DISPATCH-LEVEL。中断自旋锁通过调用KeSynchronizeExecution函数实现, 执行程序自旋锁通过调用KeAcquireSpinLock 和KeReleaseSpinLock 函数来实现。 程序自旋锁的使用如下面的代码所示: BOOLEAN NTAPI CheckBusyAndStall (PDEVQUEUE pdq) { … KIRQL oldirql ; KeAcquireSpinLock(&pdq - > lock , &oldirql) ; BOOLEAN busy = pdq - > CurrentIrp ! = NULL ; if ( !busy) InterlockedIncrement (&pdq - > stallcount) ; KeReleaseSpinLock(&pdq - > lock , oldirql) ; … } 中断自旋锁的使用如下面的代码所示: VOID Startio ( IN PDEVICE-OBJECT fdo , IN PIRP Irp) { … //PP如果必须,同步中断(用中断自旋锁) if ( dx - > ConnectedToInterrupt) { if ( ( !KeSynchronizeExecution( dx - > InterruptObject , (PKSYNCHRONIZE-ROUTINE) RunCmdsSynch ,(PVOID) fdo) ) status = STATUS-UNSUCCESSFUL ; } else … } 自旋锁的名字来自它的特性,在试图加锁的时候,如果当前锁已经处于”锁定”状态,加锁进程就进行”旋转”,用一个死循环测试锁的状态,直到成功的取得锁。自旋锁的这种特性避免了调用进程的挂起,用”旋转”来取代进程切换。而我们知道上下文切换需要一定时间,并且会使高速缓冲失效,对系统性能影响是很大的,所以自旋锁在多处理器环境中非常方便。当然,被自旋锁所保护的”临界代码”一般都比较短,否则就会浪费过多的CPU资源。 为了获得一个自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其它CPU不可能访问这个内存变量。如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行。如果测试结果表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置(test-and-set)”操作,即开始“自旋”。最后,锁的所有者通过重置该变量释放这个自旋锁,于是,某个等待的test-and-set操作向其调用者报告锁已释放。 为了明确地使用一个自旋锁,首先要在非分页内存中为一个KSPIN_LOCK对象分配存储。然后调用KeInitializeSpinLock初始化这个对象。接着,当代码运行在低于或等于DISPATCH_LEVEL级上时获取这个锁,并执行需要保护的代码,最后释放自旋锁。使用KeAcquireSpinLock获取自旋锁,它把IRQL提升到DISPATCH_LEVEL级上。 使用KeReleaseSpinLock释放自旋锁时,它把IRQL降低到原来的IRQL级上。 关于自旋锁有两个明显的事实。 第一,如果一个已经拥有某个自旋锁的CPU想第二次获得这个自旋锁,则该CPU将死锁(deadlock)。自旋锁没有与其关联的“使用计数器”或“所有者标识”;锁或者被占用或者空闲。如果你在锁被占用时获取它,你将等待到该锁被释放。如果碰巧你的CPU已经拥有了该锁,那么用于释放锁的代码将得不到运行,因为你使CPU永远处于“测试并设置”某个内存变量的自旋状态。 关于自旋锁的另一个事实是,CPU在等待自旋锁时不做任何有用的工作,仅仅是等待。所以,为了避免影响性能,你应该在拥有自旋锁时做尽量少的操作,因为此时某个CPU可能正在等待这个自旋锁。 关于自旋锁还存在着一个不太明显但很重要的事实:你仅能在低于或等于DISPATCH_LEVEL级上请求自旋锁,在你拥有自旋锁期间,内核将把你的代码提升到DISPATCH_LEVEL级上运行。在内部,内核能在高于DISPATCH_LEVEL的级上获取自旋锁,但你和我都做不到这一点。 所以对于单CPU来说, 应该用信号量来保护临界代码。 虽然相比较多CPU情形下的自旋锁稍慢一些(因为操作信号量不成功就会切换进程, 而不会像自旋锁一样不停地执行), 但是这似乎是目前唯一可取的方法了。 July 25 Author:云风 Source URL:http://blog.codingnow.com/2005/10/vc_memcpy.html 在很多编译器中,memcpy 是一个 intrinsic 函数,也就是说,这个函数是由编译器实现的。它比 inline 函数更容易被编译时优化。编译器可以根据 memcpy 的参数是常量还是变量做出多种版本,达到最佳的性能。这一点,用 inline 或者 template 的技巧都无法办到。 我们看看 VC 对 memcpy 的优化。(所用版本 VC6) void foo(void *d,const void *s) { memcpy(d,s,1); } 选性能最优化,生成汇编代码可以看到。代码被优化成: mov eax, DWORD PTR _s$[esp-4] mov edx, DWORD PTR _d$[esp-4] mov cl, BYTE PTR [eax] mov BYTE PTR [edx], cl 只是一个字节拷贝,用 cl 寄存器 mov 完成的。 把 1 改成 4 后: mov eax, DWORD PTR _s$[esp-4] mov edx, DWORD PTR _d$[esp-4] mov ecx, DWORD PTR [eax] mov DWORD PTR [edx], ecx 就变成了一条最普通的 mov 指令。 如果是 8 个字节: mov eax, DWORD PTR _s$[esp-4] mov ecx, DWORD PTR _d$[esp-4] mov edx, DWORD PTR [eax] mov DWORD PTR [ecx], edx mov eax, DWORD PTR [eax+4] mov DWORD PTR [ecx+4], eax 就是两条 mov 指令。 直到长度是常量 19 还是用 mov 完成的: mov eax, DWORD PTR _s$[esp-4] mov ecx, DWORD PTR _d$[esp-4] mov edx, DWORD PTR [eax] mov DWORD PTR [ecx], edx mov edx, DWORD PTR [eax+4] mov DWORD PTR [ecx+4], edx mov edx, DWORD PTR [eax+8] mov DWORD PTR [ecx+8], edx mov edx, DWORD PTR [eax+12] mov DWORD PTR [ecx+12], edx mov dx, WORD PTR [eax+16] mov WORD PTR [ecx+16], dx mov al, BYTE PTR [eax+18] mov BYTE PTR [ecx+18], al 长度达到 20 后,就转变成了使用 rep movsd push esi mov esi, DWORD PTR _s$[esp] push edi mov edi, DWORD PTR _d$[esp+4] mov ecx, 5 rep movsd pop edi pop esi 如果长度并非 4 的整数倍的话,比如复制 23 个字节: push esi mov esi, DWORD PTR _s$[esp] push edi mov edi, DWORD PTR _d$[esp+4] mov ecx, 5 rep movsd movsw movsb pop edi pop esi 编译器会在后面插入 movsw 和 movsb 。 现在我们来看看,memcpy 的长度是变量的情况: void foo(void *d,const void *s,size_t size) { memcpy(d,s,size); } 这次编译器直接调用了 rep movsd mov ecx, DWORD PTR _size$[esp-4] push esi mov esi, DWORD PTR _s$[esp] mov eax, ecx push edi mov edi, DWORD PTR _d$[esp+4] shr ecx, 2 rep movsd mov ecx, eax and ecx, 3 rep movsb pop edi pop esi 因为我们并不知道 size 是否是 4 的整数倍,所以尾巴上用 and ecx,3 / repmovsb 来处理了一下。 那么我们能否通知编译器,需要 memcpy 的数据块长度是 4 的倍数呢?答案是可以的。看看编译器怎么编译 memcpy(d,s,size*4); mov ecx, DWORD PTR _size$[esp-4] push esi mov esi, DWORD PTR _s$[esp] push edi mov edi, DWORD PTR _d$[esp+4] rep movsd pop edi pop esi 非常简洁,不是吗? July 20 What is Reverse Engineering? Reverse engineering is the process of extracting the knowledge or design blue-prints from anything man-made. The concept has been around since long before computers or modern technology, and probably dates back to the days of the industrial revolution. It is very similar to scientific research, in which a researcher is attempting to work out the "blueprint" of the atom or the human mind. The difference between reverse engineering and conventional scientific research is that with reverse engineering the artifact being investigated is man-made, unlike scientific research where it is a natural phenomenon. 这两天晚上,一直都上不去网,好象定时了一样,每天晚上8-9点左右就上不起网... 10000号也打了两次,没来人.......今天突发奇想,是不是因为开了空调,电压太低上不起网,把空调关了,果然行了.汗一个!!! 不是电压低的原因, 今天第三次打10000号,这次学乖了,跟那接线MM聊完,搭上一句,麻烦帮忙搞好,靓妹...嘿嘿!果然就可以上网了.:) 最后确认, 线路故障, 从电信门子出来的接口处, 因为暴露在外面, 几乎完全锈断, 只粘上一线线了, 可就是因为这一线线, 一天总能跟电信局服务端物理连接上一,两次,但只要有数据传输, 铁定掉线, 而且再也连不上了...狂吐血~~~
|