32: 之前在病毒里涉及到很多时候都要用kernel32.dll的基址 通过这个基址搜索EAT来获得导出函数LoadLibrary和GetProcAddress 然后利用这两个函数获取其他的函数,当然也可以直接搜索导出表获得想要的函数! 现在装了win7,测试之前写的病毒不起作用,调试发现基址是错误的!虽然是64位系统,但是Wow64下面应该是可以运行的!所以确定必然是基址的获得方法有改变。 第一种方法------------- xor ebx, ebx mov ebx, fs:[ 0x30 ] ;PEB mov ebx, [ ebx + 0x0C ] ;PEB->Ldr mov ebx, [ ebx + 0x1C ] ;PEB->Ldr.InInitializationOrderModuleList.Flink mov ebx, [ ebx ] ;next entry mov ebx, [ ebx + 0x08 ] ;base address (kernel32.dll) 在xp vista 2000上都是这样的!运行没有问题! 但是win7上面在加载kernel32.dll之前要先加载kernelbase.dll 所以mov ebx,[ebx]的时候实际上是接近了kernelbase.dll 所以要获得kernel32.dll我们需要修正下之前的做法 第二种方法: xor ebx, ebx mov ebx, fs:[ 0x30 ] ;PEB mov ebx, [ ebx + 0x0C ] ;PEB->Ldr mov ebx, [ ebx + 0x14 ] ;PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry) mov ebx, [ ebx ] ;next entry (2nd entry) mov ebx, [ ebx ] ;entry (3rd entry) mov ebx, [ ebx + 0x10 ] ;base address (kernel32.dll) 但是我的一个外国朋友bitRAKE说,这样貌似在2000上有些时候是失效的,问题就在InMemoryOrderModuleList的地址上! 更为妥当而且稳定的方法是这样的(多做一些判断): 第三种方法: cld xor edx, edx mov edx, [fs:edx+0x30] ;PEB mov edx, [edx+0x0C] ;PEB->Ldr mov edx, [edx+0x14] ;;PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry) next_mod: mov esi, [edx+0x28] ;modules name (unicode string) push byte 24 ;push down the length we want to check pop ecx xor edi, edi ;store the hash of the module name loop_modname: xor eax, eax lodsb cmp al, 'a' ;some versions of Windows use lower case module names jl not_lowercase sub al, 0x20 ;up not_lowercase: ror edi, 13 add edi, eax ;add the next byte of the name to the hash loop loop_modname cmp edi, 0x6A4ABC5B ;compare the hash with that of KERNEL32.DLL mov ebx, [edx+0x10] ;get this modules base address mov edx, [edx] ;get the next module jne next_mod 现在ebx里面就是kernel32的基址 那么在我们写个程序在我当前的系统上做个测试(win7 x64) 测试结果是这样的: ------------------------------------------------------------- GetModuleHandleA( "kernelbase.dll" ) = 0x75030000 GetModuleHandleA( "kernel32.dll" ) = 0x75360000 GetModuleHandleA( "ntdll.dll" ) = 0x76F20000 ------------------------------------------------------------- Method 1: Kernel32 Base Address = 0x75030000 (Correct: NO!) Method 2: Kernel32 Base Address = 0x75360000 (Correct: YES) Method 3: Kernel32 Base Address = 0x75360000 (Correct: YES) ------------------------------------------------------------- 很显然之前的方法一是不行了。呼呼!! 这样的方法是比较稳妥的。 64: 我跟bitRAKE说,我想研究64位,他回答我说,你根本没有必要专门的来研究64,只需要找到你最拿手的领域稍微的修改下就可以了! 我有点感叹,中国人看到64不敢尝试,甚至排斥,说什么现在32呢还早呢!!!根本不是一个思路想问题,那么我们也这样的来尝试下,仅仅把64作为一个稍微改进了的机制。 不要把它认为是多么难搞的东西! 具体的64 的东西我不提,第一,我也初涉及,第二,有的是官方文档。 貌似国外的derko针对x64写过类似的东西,而且也进行了其他几个方面的研究(要承认国外研究64比我们要早,这不可否认)是这样的: xor rdx, rdx ; Zero rdx mov rdx, [gs:rdx+96] ; Get a pointer to the PEB mov rdx, [rdx+24] ; Get PEB->Ldr mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list next_mod: ; mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) movzx rcx, word [rdx+74] ; Set rcx to the length we want to check xor r9, r9 ; Clear r9 which will store the hash of the module name loop_modname: ; xor rax, rax ; Clear rax lodsb ; Read in the next byte of the name cmp al, 'a' ; Some versions of Windows use lower case module names jl not_lowercase ; sub al, 0x20 ; If so normalise to uppercase not_lowercase: ; ror r9d, 13 ; Rotate right our hash value add r9d, eax ; Add the next byte of the name loop loop_modname ; Loop untill we have read enough ; We now have the module hash computed push rdx ; Save the current position in the module list for later push r9 ; Save the current module hash for later ; Proceed to itterate the export address table, mov rdx, [rdx+32] ; Get this modules base address 我用fasm写过一个测试程序,上面的方法没有成功! fdbg跟踪了下: 0000000000402018 65488B5260 GS mov rdx,[rdx+60] ; [000007FFFFFDE060]=000007FFFFFD3000 这里应该是PEB的地址 我用windbg查看的时候貌似看到peb应该是在000007fffffda000,,所以这里没有获得有效的东西! 可是又想,win7里面有动态基址的技术(是win7 不是64 cpu)也就是说PEB的地址对于不同的进程是不一样的! 我拿起windbg有看了下,peb at 000007fffffd8000,,,,,,,,法克and史特 那么想到用函数来动态的获取! NtCurrentTeb?呼呼。然后从teb获取peb!! 貌似这样做是克瑞科特的! 我还是不心甘,简单修改了下上面那个: mov rax,[gs:30h] ; RAX points to TEB (Thread Environment Block) mov rcx,[rax+60h] ; RCX points to PEB (Process Environment Block) 考虑代码的优化,也可以这样写: push 60h pop rsi gs lodsq ; RAX points to PEB 我写了个测试的程序: ;-----------------------------------------------------------------------------; ; Author: charme (http://www.x64asm.com/) ; Compatible: Windows 7(i only test about this,OTHER maybe) ; Architecture: x64 ; Size: 3kb ;-----------------------------------------------------------------------------; ;then our coce start,have a fun! format PE64 GUI include 'C:\asm\tool\fasm\fasmw\INCLUDE\win64axp.inc' ;this is only for the macro ;but not apis and libs ;bcs we get the address by ourselfs ;surely .data crc db 400h dup (?) sz db 'charme',0 szformat db 'baseaddr=0x%.16IX',0 buff rb 1024 .code start: ;;stack cld sub rsp,8*(4+4-1) ;;bcs the .code macro has 'sub rsp,8h' push rsi push 60h pop rsi gs lodsq ; RAX points to PEB mov rdx,rax mov rdx,[rdx+24] ;;PEB->Ldr mov rdx,[rdx+32] ;;first module(InMemoryOrder module list) next_mod: ; mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) movzx rcx, word [rdx+74] ; Set rcx to the length we want to check xor r9, r9 ; Clear r9 which will store the hash of the module name loop_modname: xor rax, rax ; Clear rax lodsb ; Read in the next byte of the name cmp al, 'a' ; Some versions of Windows use lower case module names jl not_lowercase sub al, 0x20 ; If so normalise to uppercase not_lowercase: ror r9d, 13 ; Rotate right our hash value add r9d, eax dec rcx test rcx,rcx jne loop_modname cmp r9d,092af16dah ;;kernel32.dll jne _next mov RbX,[RDX+32] xchg rbx,rax lea rcx,[buff] lea rdx,[szformat] mov r8,rax call [wsprintf] xor r9,r9 lea r8,[sz] lea rdx,[buff] xor rcx,rcx call [MessageBoxA] jmp _exit _next: mov rdx,[rdx] jmp next_mod _exit: add rcx,8*(4+4-1) xor rcx,rcx call [ExitProcess] .end start 输出结果: baseaddr:000000076B20000H 我还没有搭建好windbg!没有办法验证!不过我估计是没有问题的!