: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 下一页 |