;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; 程序函数说明:利用fs寄存器,得到任意的函数地址 ; by:瀚 海 2011年11月19日 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ;很早之前就知道利用fs可以导出kernel32!LoadLibrary、Kernel32!GetProcAddress函数 ;也就可以得到任意dll的任意函数,一直不清楚到底哪个数据偏移多少位置。最近开始弄安全 ;所以顺便弄下shellcode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .386 .model flat,stdcall option casemap:none include windows.inc .data DllName db 'ExitProcess',0 .data? Count dd ? assume fs:nothing ;打开FS寄存器,否则用到FS寄存器的编译都不会通过 .code ;得到字符串长度 ;相同返回0,不同返回1,便于后面可以使用C语言库的strcmp函数 strcmp proc uses edi esi ebx ecx source:dword,dst:dword xor eax,eax ;判断来源是不是有NLL地址,如果有,直接当成不等字符串 mov esi,source test esi,esi je NotEQual mov edi,dst test edi,edi je NotEQual ;判断两字符是否有为'\0'结尾的字符串,有一个不为'\0'则将继续比较 ;直到遇到不等字符或两个都为'\0'字符 cmpNext: mov bl,byte ptr[esi] test bl,bl jnz TestNextZ cmp byte ptr[edi],0 je szEqual ;两字符串都以'\0'结尾,那么他们是相同字符串 TestNextZ: mov cl,byte ptr[edi] inc edi inc esi cmp bl,cl jnz NotEQual jmp cmpNext NotEQual: inc eax szEqual: ret strcmp endp ;得到字符串长度函数 ;这个函数在其他地方copy的 strlen proc uses ecx edi szString:dword mov edi,szString xor ecx,ecx dec ecx xor al,al repne scasb not ecx dec ecx xchg eax,ecx ret strlen endp ;得到任意函数地址 ;如果函数不在Kernel32.dll中可以利用LoadLibrary、GetProcAddress加载其他函数 GetProcessAddress proc uses edx esi ecx ebx dllName:DWORD mov eax,dword ptr fs:[30H] ;得到TEB结构 mov eax,dword ptr [eax+0CH] ;得到PEB_LDR_DATA结构 mov esi,dword ptr [eax+1CH] ;InInitializationOrderModuleList ;得到Kernel32.dll所在LDR_MODEL结构的InInitializationOrderModuleList地址 lodsd mov edx,dword ptr[eax+8H] ;得到BaseAddress,即kernel32基址 push edx mov ecx,dword ptr[edx+3CH] ;edx指向kernel32的内存映像基址,得到PE头指针 lea ecx,dword ptr[edx+ecx] ;ecx,指向PE头 mov ecx,dword ptr[ecx+78H] ;指向导出表 lea ecx,dword ptr[edx+ecx] ;ecx指向导出表 mov ebx,dword ptr[ecx+1CH] lea ebx,dword ptr[edx+ebx] ;ebx指向函数地址列表 push ebx ;先保存函数地址列表首地址 mov ebx,dword ptr[ecx+0CH] ;网上有说这个地址是偏移0x20的,不清楚是不是系统版本问题 lea ebx,dword ptr[edx+ebx] ;ebx指向函数名称列表,第一个是kernel32.dll ; push ebx ;有必要的话,可以保存下 @@: inc Count ;函数序号+1 mov eax,Count cmp eax,3BBH ;XP中只有954个函数,超过的就错误了 jge @F invoke strlen,ebx ;ebx指向下一个字符串首地址,第一次指向"kernel32.dll"字符串 lea ebx,dword ptr[eax+ebx+1] invoke strcmp,dllName,ebx ;比较字符串,相同返回0 cmp eax,0 jnz @B dec Count ;得到函数的序号,也可以当成是函数表中的第几个函数 mov eax,Count shl eax,2 ;每个地址32位,所以要乘以4 pop ebx ;弹出函数地址列表首地址 mov ebx,dword ptr[ebx+eax] ;得到函数的偏移地址 pop edx ;弹出kernel32首地址 lea eax,dword ptr[edx+ebx] ;得到函数地址 @@: ret GetProcessAddress endp start: xor eax,eax mov Count,eax ;调用查找函数地址函数,返回eax中是函数地址,如果函数不存在返回小于0xFFFFF的值 invoke GetProcessAddress,offset DllName .if eax > 0FFFFFH push NULL call eax ;调用ExitProcess函数 .endif ;如果没有这个函数,那么手动处理错误 end start