【ChinaBeta.Cn 网盟学院】
Protection Weakness: I have used a fixed value for the number of cycles: E0000h. I could have (Actually i can do it with my layer generator) used a random value rather than a constant and therefore, making the scan for this constant useless. I could also have used different instructions for each SEH to make the creation of a generic pattern difficult. The biggest weakness of this detection is the constant and the usage of the same instructions for every checks. It is also possible to write a Kernel Module Driver to catch every execution of RDTSC (See Intel documentation for further informations) and return very similar values, thus bypassing the detection completely.
保护漏洞: 我使用了上限E0000H。然而我可以使用任意数值代替这个常数。另外我还可以对每个SEH使用不同的指令使其产生不同的效果。最大的漏洞就是常数的设置和每个校验使用相同的指令。因此,我们可以写出一段Kernel Module Driver,去截获RDTSC的执行并返回相似的数值,以此击败这种保护方式。
? BPX Detection: As we are going to use API functions, We have to protect them from beeing BPX'ed by an attacker. Rather than Using GetProcAddress to get the API address and then to check for an int 3 opcode (0xCC) in the API function code, i have used a different method. I directly access the Import Table , more precisely, the Import Address Table to read the API function address and then start to search for breakpoints. The int 3 opcode is 0xCC and is known by Reverse Engineers. In order to make a little less obvious, i have obfuscated the breakpoint check using a "SHR" (Shift Right) instruction: 0x660 shr 3 = 0xCC ;-). The program will then check four bytes at API function entry point, looking for a breakpoint. If a breakpoint is found, i have used a funny way to crash the application. Im using RDTSC to generate a pseudo random number and i put this number onto the stack. To modify EIP, i simply use the RET instruction, which will transfer us to random memory address, crashing our application. Each time a detection occurs, the address is different, thus hard to monitor. The crash occurs far from the detection code and Soft ICE's FAULT ON won't catch it either.
BPX侦测: 当使用API函数时,我们需要防止攻击者利用BPX作恶。一般的方法是:使用GetProcAddress得到API地址并在函数代码中检测INT3操作码,而我使用了另一种不同的方法:从导入地址表获取API函数的地址然后查找断点。大家都知道,INT3的操作码是0xCC。为了使其更具迷惑性,我使用了“SHR”这种指令:0x660 shr 3=0xCC。程序API函数的入口点中校验开始四个字节,查找断点。一旦发现,就使程序崩溃。我使用RDTSC产生一个随机的数值,并把此值放入堆栈并修改返回地址,通过RET指令将会跳转到任意一个内存地址中,从而使程序崩溃。而且每次侦测的地址都不同也无法监测。崩溃距离引发崩溃的代码很远,就连SoftIce的FAULT ON功能也无法实现。
Protection Weakness: First, the Imports aren't protected, therefore anyone can read the Imported functions from the binary. From The import table we can see that printf, GetCommandLineA and ExitProcess are used. This is a weakness. A Reverse Engineer can put breakpoints on those functions, or at least, guess they are going to be used at some point. In the case of our binary, one can guess that the application is waiting for a special command line. A solution would be to load the Import Table manually.
保护漏洞: 首先,导入表未受保护,因此任何人都可以从代码中读取输入函数。从导入表中,我们可以发现如printf,GetCommandLineA和ExitProess 语句的使用。这是一个漏洞。逆向者可以在上述地方下断点或预测它们将会被调用的地址。以代码为例,我们可以预测到程序正在等待一项特殊的命令行命令。而对策就是手动加载导入表。
For this we could use a home made GetProcAddress function to browse the Export Table of the dlls we want to import functions from, and then, get the address of the API function from there. A Kernel32 address is always on the stack when a binary is started, so we could have used this value to get the dll's ImageBase (Or use the PEB, SEH chaining etc..). We would have everything needed to get the address of Loadlibrary which allows us to Load ANY dll, and thus, to get the address of ANY API function. With this method, we don't need any Import Table at all.
这样说来,我们可以通过自己手写的GetProcAddress浏览dll的导出表函数来获取需要导入的API地址。当应用程序运行时,堆栈中的Kernel32地址可以帮助我们得到dll的基址(或使用PEB,SHE链等)。我们从装载dll的Loadlibrary的地址处得到所有API函数的地址,而无须借助任何输入表。
Well actually, this isn't true. There is a mandatory thing to do to keep compatibility with all versions of Windows. We have to create a very small Import Table, with at least ONE import from Kernel32, else the binary won't run on Windows 2000. The Windows 2000 PE Loader is different from the one in Windows XP. XP doesn't care whether there is any import table or not.
事实上,这并不完全正确。为了与各个版本的Windows兼容,输入表是必须的。我们需要建立一个很小的导入表,至少要包括一个Kernel32中的输入,否则2000中将无法运行。因为2000与XP的PE装载器是不同的,后者并不在乎是否有输入表存在。
The small Import Table is just for compatibility issue, the real import table is encrypted and will be decrypted at runtime by the protection.Then, it is just a matter of loading the Imports mimicing the Operating System. We need to put the API address in the Import Address Table (of the decrypted Import Table) manually. The Reverse Engineer has no clue about the API functions used by the binary until he gets to the part of the code that will decrypt and load the Imports.
这种导入表完全是为了兼容而服务,真正的导入表已经被加密并在运行时被保护代码解密。然后模拟系统装载导入表的过程,我们需要手工的把API地址放到IAT(解密过的导入表)中。逆向引擎只有在解密并装载了导入表后才能获取应用程序所调用的API函数。上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] 下一页
(责任编辑:hahack)
|