- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- ; 程序函数说明:利用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
利用FS寄存器得到任意函数地址
最新推荐文章于 2024-04-14 11:51:26 发布