【破文标题】Windows系统RunAs命令的DIY改造
【破文作者】FishSeeWater
【作者主页】htp://shuihua.hostrocket.com
【作者邮箱】yujianshui99@163.com
【所属组织】BCG
【软件名称】RunAs.EXE
【下载地址】Microsoft的
【破解工具】OllyDbg(cao_cong汉化版) + C32Asm
【保护方式】无
【软件限制】不接受密码参数
【破解难度】简单
-----------------------------------------------------------------
【软件介绍】
    Microsoft系统自带的命令,不用我多罗嗦了吧:)
-----------------------------------------------------------------
【DIY声明】
    最近由于公司领导要求“计算机资料保密”,我决定采用WIN2000的系统特性加上NTFS权限完成。用Win2003架了台服务器,然后为每位工程师建了User帐户,但是发现好几个CAD软件在User用户下没法运行,但通过右键的“运行方式”以"Administrator"运行就没事儿,调整组权限,整了好几天也没能搞定,微软出于安全考虑 RunAs 命令不能直接跟密码参数。每次都要单独输入密码,这样的话那我岂不要~~*&@#$$@:(。在网上找RunAs命令的程序实现方式,准备写个程序调用CAD来运行,可是用LogonUser();CreateProcessAsUse();CreateProcessWithLogonW()这几个函数死活不行,LogonUser()总是返加1314错误,郁闷。无奈之下,还是打RunAs的主意吧。让它支持密码参数不就OK了:)
-----------------------------------------------------------------
【破解分析】
    好!开始:

    首先预习一下基础知识,控制台程序获取运行参数是用GetCommandLine(VOID)函数
    打开OD加载目标程序,参数为 "/user:administrator cmd.exe"
然后下断点BPX GetCommandLine 回车
F9运行,程序断在01001572 CALL DWORD PTR DS:[<&KERNEL32.GetCommandLineW>; |[GetCommandLineW

瞧瞧它是怎样RunAs的:)
F8一步一步走:
[CODE]
01001555  |.  50   PUSH EAX                                      ; /pArgc
01001556  |.  895D>MOV DWORD PTR SS:[EBP-1C],EBX                 ; |
01001559  |.  895D>MOV DWORD PTR SS:[EBP-20],EBX                 ; |
0100155C  |.  895D>MOV DWORD PTR SS:[EBP-C],EBX                  ; |
0100155F  |.  895D>MOV DWORD PTR SS:[EBP-18],EBX                 ; |
01001562  |.  895D>MOV DWORD PTR SS:[EBP-38],EBX                 ; |
01001565  |.  8975>MOV DWORD PTR SS:[EBP-4],ESI                  ; |
01001568  |.  895D>MOV DWORD PTR SS:[EBP-14],EBX                 ; |
0100156B  |.  C745>MOV DWORD PTR SS:[EBP-7C],44                  ; |
//得到参数
01001572  |.  FF15>CALL DWORD PTR DS:[<&KERNEL32.GetCommandLineW>; |[GetCommandLineW
01001578  |.  50   PUSH EAX                                      ; |CmdLine
//得到参数个数
01001579  |.  FF15>CALL DWORD PTR DS:[<&SHELL32.CommandLineToArg>; \CommandLineToArgvW
0100157F  |.  8BC8 MOV ECX,EAX
01001581  |.  3BCB CMP ECX,EBX
01001583  |.  894D>MOV DWORD PTR SS:[EBP+8],ECX
01001586  |.  0F85>JNZ runas.0100163E
0100158C  |.  895D>MOV DWORD PTR SS:[EBP-4],EBX
.......
.......
.......
//比较参数个数,不等于3就跳走,显示RunAs的帮助(自身的程序名也算一个参数)
0100163E  |> \8B45>MOV EAX,DWORD PTR SS:[EBP-14]
01001641  |.  83F8>CMP EAX,5
01001644  |.  74 0>JE SHORT runas.01001650
01001646  |.  83F8>CMP EAX,4
01001649  |.  74 0>JE SHORT runas.01001650
0100164B  |.  83F8>CMP EAX,3
0100164E  |.  75 7>JNZ SHORT runas.010016CF
01001650  |>  8D50>LEA EDX,DWORD PTR DS:[EAX-2]
//以下是判断并取出第二个参数"administraor" (第一个参数是RunAs.exe)
01001653  |.  8975>MOV DWORD PTR SS:[EBP-8],ESI
01001656  |.  3BD6 CMP EDX,ESI
01001658  |.  7C 7>JL SHORT runas.010016CA
0100165A  |.  8D79>LEA EDI,DWORD PTR DS:[ECX+4]
0100165D  |>  8B07 MOV EAX,DWORD PTR DS:[EDI]
0100165F  |.  66:8>CMP WORD PTR DS:[EAX],2F
01001663  |.  75 6>JNZ SHORT runas.010016CF
01001665  |.  0FB7>MOVZX ECX,WORD PTR DS:[EAX+2]
01001669  |.  83F9>CMP ECX,4E                                    ;  Switch (cases 45..75)
0100166C  |.  7F 1>JG SHORT runas.0100167E
0100166E  |.  0F84>JE runas.01001BA4
01001674  |.  83F9>CMP ECX,45
01001677  |.  75 5>JNZ SHORT runas.010016CF
01001679  |>  8975>MOV DWORD PTR SS:[EBP-1C],ESI                 ;  Cases 45 ('E'),65 ('e') of switch 01001669
0100167C  |.  EB 4>JMP SHORT runas.010016BF
0100167E  |>  83E9>SUB ECX,50
01001681  |.  74 3>JE SHORT runas.010016BC
01001683  |.  83E9>SUB ECX,5
01001686  |.  74 1>JE SHORT runas.0100169F
01001688  |.  83E9>SUB ECX,10
0100168B  |.^ 74 E>JE SHORT runas.01001679
0100168D  |.  83E9>SUB ECX,9
01001690  |.  0F84>JE runas.01001BA4
01001696  |.  49   DEC ECX
01001697  |.  49   DEC ECX
01001698  |.  74 2>JE SHORT runas.010016BC
0100169A  |.  83E9>SUB ECX,5
0100169D  |.  75 3>JNZ SHORT runas.010016CF
0100169F  |>  83C0>ADD EAX,4                                     ;  Cases 55 ('U'),75 ('u') of switch 01001669
010016A2  |>  66:8>/MOV CX,WORD PTR DS:[EAX]
.......
.......
.......
010016CD  |. /75 0>JNZ SHORT runas.010016DC
010016CF  |> |E8 8>CALL runas.0100125B                           ;  Default case of switch 01001669
010016D4  |> |895D>MOV DWORD PTR SS:[EBP-4],EBX
010016D7  |. |E9 5>JMP runas.01001B38
//加载提示资源串"键入密码administrator:"
010016DC  |> \8B3D>MOV EDI,DWORD PTR DS:[<&USER32.LoadStringW>]  ;  USER32.LoadStringW
010016E2  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-630]
010016E8  |.  68 F>PUSH 1F4                                      ; /Count = 1F4 (500.)
010016ED  |.  50   PUSH EAX                                      ; |Buffer
010016EE  |.  68 7>PUSH 1B76                                     ; |RsrcID = STRING "Enter password for"
010016F3  |.  FF35>PUSH DWORD PTR DS:[1003020]                   ; |hInst = 01000000
010016F9  |.  FFD7 CALL EDI                                      ; \LoadStringW
010016FB  |.  8B35>MOV ESI,DWORD PTR DS:[<&USER32.CharToOemW>]   ;  USER32.CharToOemW
01001701  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-8EC]
01001707  |.  50   PUSH EAX                                      ; /pDest
01001708  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-630]                ; |
0100170E  |.  50   PUSH EAX                                      ; |pSrc
0100170F  |.  FFD6 CALL ESI                                      ; \CharToOemW
01001711  |.  FF75>PUSH DWORD PTR SS:[EBP-C]                     ; /String
01001714  |.  8B1D>MOV EBX,DWORD PTR DS:[<&KERNEL32.lstrlenW>]   ; |kernel32.lstrlenW
0100171A  |.  FFD3 CALL EBX                                      ; \lstrlenW
0100171C  |.  3D F>CMP EAX,1F4
01001721  |.  76 0>JBE SHORT runas.0100172E
01001723  |.  8B45>MOV EAX,DWORD PTR SS:[EBP-C]
01001726  |.  66:8>AND WORD PTR DS:[EAX+3E6],0
0100172E  |>  8D85>LEA EAX,DWORD PTR SS:[EBP-D9C]
01001734  |.  50   PUSH EAX
01001735  |.  FF75>PUSH DWORD PTR SS:[EBP-C]
01001738  |.  FFD6 CALL ESI
0100173A  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-D9C]
01001740  |.  50   PUSH EAX                                      ; /<%s>
01001741  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-8EC]                ; |
01001747  |.  50   PUSH EAX                                      ; |<%s>
01001748  |.  68 8>PUSH runas.0100118C                           ; |format = "%s %s:"
0100174D  |.  FF15>CALL DWORD PTR DS:[<&MSVCRT.printf>]          ; \printf
01001753  |.  83C4>ADD ESP,0C
01001756  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-248]
//这个104是干嘛的?难道是最大长度?请高手指点:)
0100175C  |.  68 0>PUSH 104                                      ; /Arg2 = 00000104
//压入变量地址
01001761  |.  50   PUSH EAX                                      ; |Arg1
//下面是调用ReadConsoleW函数读取键盘输入的密码
01001762 >|.  E8 4>CALL runas.010011B0                           ; \读入密码
01001767  |.  85C0 TEST EAX,EAX
01001769  |.  74 4>JE SHORT runas.010017AD
0100176B  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-630]
........
........
........
0100179B  |.  68 3>PUSH runas.01001134                           ; |format = "%s"
010017A0  |.  FF15>CALL DWORD PTR DS:[<&MSVCRT.printf>]          ; \printf
010017A6  |.  59   POP ECX
010017A7  |.  59   POP ECX
010017A8  |.  E9 4>JMP runas.010019ED
//处理输入的密码
010017AD  |>  8D85>LEA EAX,DWORD PTR SS:[EBP-248]
010017B3  |.  50   PUSH EAX                                      ; /Translation
010017B4  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-248]                ; |
010017BA  |.  50   PUSH EAX                                      ; |OemString
010017BB  |.  FF15>CALL DWORD PTR DS:[<&USER32.OemToCharA>]      ; \OemToCharA
010017C1  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-248]
//将密码复制后保存
010017C7  |.  50   PUSH EAX                                      ; /<%S>
010017C8  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-1198]               ; |
010017CE  |.  68 8>PUSH runas.01001184                           ; |Format = "%S"
010017D3  |.  50   PUSH EAX                                      ; |s
010017D4  |.  FF15>CALL DWORD PTR DS:[<&USER32.wsprintfW>]       ; \wsprintfW
010017DA  |.  83C4>ADD ESP,0C
010017DD  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-E0]
010017E3  |.  6A 3>PUSH 32
010017E5  |.  50   PUSH EAX
010017E6  |.  68 7>PUSH 1B77
010017EB  |.  FF35>PUSH DWORD PTR DS:[1003020]                   ;  runas.01000000
010017F1  |.  FFD7 CALL EDI
010017F3  |.  8B45>MOV EAX,DWORD PTR SS:[EBP-14]
010017F6  |.  8B4D>MOV ECX,DWORD PTR SS:[EBP+8]
//得到命令行参数的第三个参数长度。(DS:[ECX+EAX*4-4]为第三个参数)
010017F9  |.  FF74>PUSH DWORD PTR DS:[ECX+EAX*4-4]
010017FD  |.  FFD3 CALL EBX                                      ;  kernel32.lstrlenW
010017FF  |.  8BF8 MOV EDI,EAX
01001801  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-E0]
01001807  |.  50   PUSH EAX
01001808  |.  FFD3 CALL EBX
0100180A  |.  FF75>PUSH DWORD PTR SS:[EBP-C]
........
........
........
01001A0B  |.  C745>MOV DWORD PTR SS:[EBP-24],400
01001A12  |.  EB 0>JMP SHORT runas.01001A17
01001A14  |>  8B5D>MOV EBX,DWORD PTR SS:[EBP-38]
01001A17  |>  8D45>LEA EAX,DWORD PTR SS:[EBP-34]
//调用CreateProcessWithLogonW函数以"administrator"身份创建进程
01001A1A  |.  50   PUSH EAX                                      ; /Arg11
01001A1B  |.  8D45>LEA EAX,DWORD PTR SS:[EBP-7C]                 ; |
01001A1E  |.  50   PUSH EAX                                      ; |Arg10
01001A1F  |.  8B45>MOV EAX,DWORD PTR SS:[EBP-14]                 ; |
01001A22  |.  53   PUSH EBX                                      ; |Arg9
01001A23  |.  FF75>PUSH DWORD PTR SS:[EBP-20]                    ; |Arg8
01001A26  |.  FF75>PUSH DWORD PTR SS:[EBP-24]                    ; |Arg7
01001A29  |.  FF74>PUSH DWORD PTR DS:[EDI+EAX*4-4]               ; |Arg6
01001A2D  |.  8D85>LEA EAX,DWORD PTR SS:[EBP-1198]               ; |
01001A33  |.  6A 0>PUSH 0                                        ; |Arg5 = 00000000
01001A35  |.  FF75>PUSH DWORD PTR SS:[EBP-10]                    ; |Arg4
01001A38  |.  50   PUSH EAX                                      ; |Arg3
01001A39  |.  FF75>PUSH DWORD PTR SS:[EBP-18]                    ; |Arg2
01001A3C  |.  FF75>PUSH DWORD PTR SS:[EBP-C]                     ; |Arg1
01001A3F  |.  FF15>CALL DWORD PTR DS:[<&ADVAPI32.CreateProcessWi>; \CreateProcessWithLogonW
01001A45  |.  85C0 TEST EAX,EAX
01001A47  |.  0F85>JNZ runas.01001B36
01001A4D  |.  33FF XOR EDI,EDI
01001A4F  |.  C745>MOV DWORD PTR SS:[EBP-10],7B

////////////////////////////////////
[CODE]
过程基本分析完毕,要想达到我们的目的,只要在ReadConsoleW函数之后,将我们的已有密码添上就OK了。

思路:1、先将程序中提示输入密码和读取密码的函数NOP掉!从10016e2处开始一直到1001766
      2、我们有现成的密码,也不用他来处理,所以嘛处理过程也NOP!从1007AD处开始到1007D4(哈哈,这下有足够的空间来写我们的代码了)
      3、由于我们要用参数型式添入密码,而程序中有检测参数个数的语句,所以在CommandLineToArgvW函数后,将参数个数减1。

好!开工:
  首先处理步骤1和2 
    然后修改1001586处
           01001586  JNZ runas.0100163E 为 01001586  JNZ runas.010016F2
    在010016EF处添加语句
    010016EF   JMP SHORT runas.01001767  //正常运行时跳过下面处理参数的两句  
    在010016F2处添加语句
    010016F2   DEC DWORD PTR SS:[EBP-14] //将参数个数减1
    010016F5   JMP runas.0100163E        //跳回去
  处理参数完毕,再处理密码:
  修改01001767 处
    01001767 TEST EAX,EAX 为 01001767 XOR EAX,EAX //标志位为零
  从010017AF处开始添加语句
    010017AF  MOV EAX,DWORD PTR SS:[EBP-14]
    010017B2  INC EAX      //将参数个数加1
    010017B3  MOV ECX,DWORD PTR SS:[EBP+8]  
    010017B6  NOP
    010017B7  NOP
    010017B8  MOV EAX,DWORD PTR DS:[ECX+EAX*4-4]
    010017BC  PUSH EAX                                      ; /String2
    010017BD  LEA EAX,DWORD PTR SS:[EBP-1198]               ; |
    010017C3  NOP                                           ; |
    010017C4  PUSH EAX                                      ; |String1
    010017C5  CALL DWORD PTR DS:[<&KERNEL32.lstrcpyW>]      ; \lstrcpyW
OK!!!处理完成!!!运行试试!真爽:)
再写个外壳调用就OK了:)
收工
-----------------------------------------------------------------
                                        本文章写于2006-1-25 09:04:55 By FishSeeWater