Quantcast
Channel: 看雪安全论坛
Viewing all 9556 articles
Browse latest View live

【招聘】【百度移动安全实验室】招聘移动安全研究人员

$
0
0
职位描述:
跟我一起做以项目驱动的安全研究,挑战中不断成长。

目前开放的研究方向:
1. 安全支付
2. App审计
3. GeekPwn相关
4. android root/iOS越狱相关

职位要求:
1. 3-5年安全行业经验
2. 掌握PC端/移动端病毒行为及攻防手段
3. 熟悉Android框架和Native层工作原理,或者了解iOS越狱原理和substrate相关技术
4. C++,Java,Python至少掌握两门
5. 对安全研究感兴趣,学习能力强

北京科摩多【高薪诚聘】高级驱动开发工程师

$
0
0
任职要求:1. 3年以上C或C++工作经验,2年以上驱动程序开发经验。

2. 熟悉Windows网络体系结构,精通Windows WDK/DDK API。

3. 熟悉NDIS Passthru/Filter,TDI/WFP驱动开发。

4. 熟悉常见网络通信协议,能够实现URL过滤,内容过滤和流量控制。

5. 有Ring0和Ring3 Hooking开发经验。

6. 精通Windows平台下的程序调试。

7. 熟练的英语读写能力。

8. 优秀的沟通技能和问题解决能力。

9. 团队精神和责任心。


工作职责:1. 作为COMODO HIPS软件开发小组的成员,接受组长分配的任务并按时完成。

2. 与其它团队成员保持良好合作与沟通。

3. 主要负责HIPS系统程序的开发和维护。包括:

a) 开发及维护现有的防火墙;

b) 开发及维护现有的HIPS及HOOK DLL;

c) 开发及维护服务程序;

d) 开发及维护新产品的网络功能;

4. 每日向组长报告工作情况。

调试逆向 【分享】GIF软件逆向+注册代码+补丁

$
0
0
GIF Movie Gear逆向+注册代码+补丁
1. 准备
逆向已经被前辈们搞烂了,我这里发个前段时间写的,感觉润色的可以了。有不足之处,还望大虾指出。
我是在windows 8.1 x64上进行的操作。

1.1. 获取资源
网站下载:http://www.gamani.com/gmgdown.htm,国内站点是汉化破解好的。
GIF Movie Gear4.2.3是一款GIF动画制作软件,几乎有需要 制作GIF动画的编辑功能它都有,无须再用其它的图型软件辅助。GIF Movie Gear可以处理背景透明化而且做法容易,做好的图片可以做最佳化处理使图片减肥,另外它除了可 以把做好的图片存成GIF的动画图外,还可支援PSD,JPEG,AVI,BMP,GIF,与AVI格式输出。

1.2. 受限预先查看
附件 92050
1.3. 运行
确实受限了,其实在推出时也恼人,弹窗不然直接退出要等下出现个按钮,点ok关闭。
附件 92051
1.4. 查看pe信息
貌似没有欺骗我们,没加壳
附件 92052
附件 92053
1.5. 找看看有无注册窗口Version 4.2.3
附件 92054
附件 92055
2. 定位
2.1. 程序要判断注册的对不对,首先获取输入值。
回到od,查找一些符号,这里找GetDlgItemText或者GetWindowText,这里直接找GetWindowText(因为GetDlgItemText=GetDlgItem+GetWindowText,没有找到也没关系(如LoadLibary),直接到User2.dll模块找)并且是ASCII版的。方便点的有cmdBar插件直接入下图方式下断。
附件 92056
2.2. 回到界面点ok按钮,断点起作用了,和预想的一样。
看看堆栈,或者直接Alt+F9执行到程序模块。
附件 92057
附件 92058
可以看到两次调用GetWindowTextA,后面一个call,入参是EDX和ECX,来自于获取到编辑框里的值的缓冲区[LOCAL.49]和[LOCAL.24]。控件1103是Name,1104是Code。
后面还有一个根据返回值来jz的,并且有创建注册表项的字符串。这也太明显了,太快了,怎么这个就不设防。。。

注册信息保存在注册表HKEY_LOCAL_MACHINE \Software\gamani\GIFMovieGear\2.0下的两个键SubKey = "RegName3"和SubKey = "RegCode3" ,过期时间来自HKLM\SOFTWARE\Wow6432Node\Loani\MG4\stamp,保存的是秒数。
new Date(0x540b1713 * 1000) = Sat Jan 17 1970 15:40:12 GMT+0800 (China Standard Time)
需要注意x64位,这里的调用,注册表会被重定向:
3:29:05.3795926 PM movgear.exe 5756 RegQueryValue HKCU\Software\Classes\VirtualStore\MACHINE\SOFTWARE\Wow6432Node\gamani\GIFMovieGear\2.0\RegName3 SUCCESS Type: REG_SZ, Length: 10, Data: 苏北小麦
3:29:06.8898693 AM movgear.exe 4380 RegQueryValue HKCU\Software\Classes\VirtualStore\MACHINE\SOFTWARE\Wow6432Node\gamani\GIFMovieGear\2.0\RegCode3 SUCCESS Type: REG_SZ, Length: 26, Data: mg37sfhh4045
3:29:53.9921742 AM movgear.exe 4380 RegQueryValue HKLM\SOFTWARE\Wow6432Node\Loani\MG4\stamp SUCCESS Type: REG_BINARY, Length: 4, Data: 13 17 0B 54
附件 92059
2.3. 注册获取窗口信息
代码:

CPU Disasm
地址        十六进制数据            指令                                      注释
004344F9  |> \8BBC24 2C0100 MOV EDI,DWORD PTR SS:[ARG.1]            ; 事例 1 of switch movgear.4344D1
00434500  |.  8B35 D0F44700 MOV ESI,DWORD PTR DS:[<&USER32.GetDlgIte
00434506  |.  6A 64        PUSH 64                                  ; /MaxCount = 100.
00434508  |.  8D5424 64    LEA EDX,[LOCAL.49]                      ; |
0043450C  |.  52            PUSH EDX                                ; |String => OFFSET LOCAL.49
0043450D  |.  68 4F040000  PUSH 44F                                ; |/ItemID = 1103.
00434512  |.  57            PUSH EDI                                ; ||hDialog => [ARG.1]
00434513  |.  FFD6          CALL ESI                                ; |\USER32.GetDlgItem
00434515  |.  8B1D 4CF34700 MOV EBX,DWORD PTR DS:[<&USER32.GetWindow ; |
0043451B  |.  50            PUSH EAX                                ; |hWnd
0043451C  |.  FFD3          CALL EBX                                ; \USER32.GetWindowTextA
0043451E  |.  6A 64        PUSH 64                                  ; /MaxCount = 100.
00434520  |.  8D8424 C80000 LEA EAX,[LOCAL.24]                      ; |
00434527  |.  50            PUSH EAX                                ; |String => OFFSET LOCAL.24
00434528  |.  68 50040000  PUSH 450                                ; |/ItemID = 1104.
0043452D  |.  57            PUSH EDI                                ; ||hDialog => [ARG.1]
0043452E  |.  FFD6          CALL ESI                                ; |\USER32.GetDlgItem
00434530  |.  50            PUSH EAX                                ; |hWnd
00434531  |.  FFD3          CALL EBX                                ; \USER32.GetWindowTextA
00434533  |.  8D8C24 C40000 LEA ECX,[LOCAL.24]
0043453A  |.  51            PUSH ECX                                ; /Arg2 => OFFSET LOCAL.24
0043453B  |.  8D5424 64    LEA EDX,[LOCAL.49]                      ; |
0043453F  |.  52            PUSH EDX                                ; |Arg1 => OFFSET LOCAL.49
00434540  |.  E8 EBFBFFFF  CALL 00434130                            ; \movgear.00434130
00434545  |.  83C4 08      ADD ESP,8
00434548  |.  85C0          TEST EAX,EAX
0043454A  |.  0F84 B6000000 JZ 00434606
00434550  |.  8D4424 10    LEA EAX,[LOCAL.69]
00434554  |.  50            PUSH EAX                                ; /pDisposition => OFFSET LOCAL.69
00434555  |.  8D4C24 10    LEA ECX,[LOCAL.70]                      ; |
00434559  |.  51            PUSH ECX                                ; |pResult => OFFSET LOCAL.70
0043455A  |.  6A 00        PUSH 0                                  ; |pSecurity = NULL
0043455C  |.  68 3F000F00  PUSH 0F003F                              ; |DesiredAccess = KEY_ALL_ACCESS
00434561  |.  6A 00        PUSH 0                                  ; |Options = REG_OPTION_NON_VOLATILE
00434563  |.  68 85F64700  PUSH OFFSET 0047F685                    ; |Class
00434568  |.  6A 00        PUSH 0                                  ; |Reserved = 0
0043456A  |.  68 84E44800  PUSH OFFSET 0048E484                    ; |Subkey = "Software\gamani\GIFMovieGear\2.0"
0043456F  |.  68 02000080  PUSH 80000002                            ; |hKey = HKEY_LOCAL_MACHINE
00434574  |.  FF15 0CF04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCreateK ; \ADVAPI32.RegCreateKeyExA
0043457A  |.  8D4424 60    LEA EAX,[LOCAL.49]
0043457E  |.  8D50 01      LEA EDX,[EAX+1]
00434581  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]
00434583  |.  40            |INC EAX
00434584  |.  84C9          |TEST CL,CL
00434586  |.^ 75 F9        \JNZ SHORT 00434581
00434588  |.  8B35 00F04700 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegSetV
0043458E  |.  2BC2          SUB EAX,EDX
00434590  |.  40            INC EAX
00434591  |.  50            PUSH EAX                                ; /DataSize
00434592  |.  8B4424 10    MOV EAX,DWORD PTR SS:[LOCAL.70]          ; |
00434596  |.  8D5424 64    LEA EDX,[LOCAL.49]                      ; |
0043459A  |.  52            PUSH EDX                                ; |Data => OFFSET LOCAL.49
0043459B  |.  6A 01        PUSH 1                                  ; |Type = REG_SZ
0043459D  |.  6A 00        PUSH 0                                  ; |Reserved = 0
0043459F  |.  68 C8F34800  PUSH OFFSET 0048F3C8                    ; |SubKey = "RegName3"
004345A4  |.  50            PUSH EAX                                ; |hKey => [LOCAL.70]
004345A5  |.  FFD6          CALL ESI                                ; \ADVAPI32.RegSetValueExA
004345A7  |.  8D8424 C40000 LEA EAX,[LOCAL.24]
004345AE  |.  8D48 01      LEA ECX,[EAX+1]
004345B1  |>  8A10          /MOV DL,BYTE PTR DS:[EAX]
004345B3  |.  40            |INC EAX
004345B4  |.  84D2          |TEST DL,DL
004345B6  |.^ 75 F9        \JNZ SHORT 004345B1
004345B8  |.  8B5424 0C    MOV EDX,DWORD PTR SS:[LOCAL.70]
004345BC  |.  2BC1          SUB EAX,ECX
004345BE  |.  40            INC EAX
004345BF  |.  50            PUSH EAX                                ; /DataSize
004345C0  |.  8D8C24 C80000 LEA ECX,[LOCAL.24]                      ; |
004345C7  |.  51            PUSH ECX                                ; |Data => OFFSET LOCAL.24
004345C8  |.  6A 01        PUSH 1                                  ; |Type = REG_SZ
004345CA  |.  6A 00        PUSH 0                                  ; |Reserved = 0
004345CC  |.  68 D4F34800  PUSH OFFSET 0048F3D4                    ; |SubKey = "RegCode3"
004345D1  |.  52            PUSH EDX                                ; |hKey => [LOCAL.70]
004345D2  |.  FFD6          CALL ESI                                ; \ADVAPI32.RegSetValueExA
004345D4  |.  8B4424 0C    MOV EAX,DWORD PTR SS:[LOCAL.70]
004345D8  |.  50            PUSH EAX                                ; /hKey => [LOCAL.70]
004345D9  |.  FF15 18F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKe ; \ADVAPI32.RegCloseKey
004345DF  |.  68 E0F34800  PUSH OFFSET 0048F3E0                    ; /Subkey = "Software\Loani\MG4"
004345E4  |.  68 02000080  PUSH 80000002                            ; |hKey = HKEY_LOCAL_MACHINE
004345E9  |.  FF15 14F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegDeleteK ; \ADVAPI32.RegDeleteKeyA
004345EF  |.  6A 01        PUSH 1                                  ; /Result = 1
004345F1  |.  57            PUSH EDI                                ; |hDialog => [ARG.1]
004345F2  |.  FF15 A4F34700 CALL DWORD PTR DS:[<&USER32.EndDialog>]  ; \USER32.EndDialog
004345F8  |.  5F            POP EDI
004345F9  |.  5E            POP ESI
004345FA  |.  33C0          XOR EAX,EAX
004345FC  |.  5B            POP EBX
004345FD  |.  81C4 1C010000 ADD ESP,11C
00434603  |.  C2 1000      RETN 10
00434606  |>  6A 30        PUSH 30                                  ; /Arg4 = 30
00434608  |.  68 159D0000  PUSH 9D15                                ; |Arg3 = 9D15
0043460D  |.  68 149D0000  PUSH 9D14                                ; |Arg2 = 9D14
00434612  |.  57            PUSH EDI                                ; |Arg1 => [ARG.1]
00434613  |.  E8 F8D8FDFF  CALL 00411F10                            ; \movgear.00411F10
00434618  |.  83C4 10      ADD ESP,10
0043461B  |.  68 4F040000  PUSH 44F                                ; /ItemID = 1103.
00434620  |.  57            PUSH EDI                                ; |hDialog => [ARG.1]
00434621  |.  FFD6          CALL ESI                                ; \USER32.GetDlgItem
00434623  |.  50            PUSH EAX                                ; /hWnd
00434624  |.  FF15 A8F44700 CALL DWORD PTR DS:[<&USER32.SetFocus>]  ; \USER32.SetFocus
0043462A  |.  5F            POP EDI
0043462B  |.  5E            POP ESI
0043462C  |.  33C0          XOR EAX,EAX
0043462E  |.  5B            POP EBX
0043462F  |.  81C4 1C010000 ADD ESP,11C
00434635  |.  C2 1000      RETN 10

2.4. 失败弹窗走
代码:

CPU Disasm
地址        十六进制数据            指令                                      注释
00411EE0  /$  8B4424 04    MOV EAX,DWORD PTR SS:[ARG.1]            ; movgear.00411EE0(推测 Arg1)
00411F51  |.  83C4 04      ADD ESP,4                                ; |
00411F54  |.  50            PUSH EAX                                ; |Text
00411F55  |.  8B8424 100100 MOV EAX,DWORD PTR SS:[ARG.1]            ; |
00411F5C  |.  50            PUSH EAX                                ; |hOwner => [ARG.1]
00411F5D  |.  FF15 C4F44700 CALL DWORD PTR DS:[<&USER32.MessageBoxA> ; \USER32.MessageBoxA
00411F63  |.  81C4 00010000 ADD ESP,100
00411F69  \.  C3            RETN

3. 关键
3.1. 看注册过程
附件 92060
我们来看看0048F3F8偏移处的值,32个黑名单
附件 92061
3.2. 第一种注册码验证过程,Code是mg37开头就是走这种的。
代码:

CPU Disasm
地址        十六进制数据            指令                                              注释
00434130  /$  53            PUSH EBX                                        ; movgear.00434130(推测 Arg1,Arg2)
00434131  |.  55            PUSH EBP
00434132  |.  8B6C24 10    MOV EBP,DWORD PTR SS:[ARG.2]                    ; EBP指向Code,ASCII "12345678"
00434136  |.  807D 00 6D    CMP BYTE PTR SS:[EBP],6D                        ; Code的第一字节,和'm'比较
0043413A  |.  56            PUSH ESI
0043413B  |.  57            PUSH EDI
0043413C  |.  0F85 AD000000 JNE 004341EF
00434142  |.  807D 01 67    CMP BYTE PTR SS:[EBP+1],67                      ; Code的第2字节,和'g'比较
00434146  |.  0F85 A3000000 JNE 004341EF
0043414C  |.  807D 02 33    CMP BYTE PTR SS:[EBP+2],33                      ; Code的第3字节,和'3'比较
00434150  |.  0F85 99000000 JNE 004341EF
00434156  |.  807D 03 37    CMP BYTE PTR SS:[EBP+3],37                      ; Code的第4字节,和'7'比较
0043415A  |.  0F85 8F000000 JNE 004341EF
00434160  |.  33DB          XOR EBX,EBX                                      ; 和黑名单库里的比较
00434162  |>  8BBB F8F34800 /MOV EDI,DWORD PTR DS:[EBX+48F3F8]              ; 到 PTR ASCII "mvg21951736"
00434168  |.  8BC7          |MOV EAX,EDI                                    ; strlen开始
0043416A  |.  8D50 01      |LEA EDX,[EAX+1]
0043416D  |.  8D49 00      |LEA ECX,[ECX]
00434170  |>  8A08          |/MOV CL,BYTE PTR DS:[EAX]
00434172  |.  40            ||INC EAX
00434173  |.  84C9          ||TEST CL,CL
00434175  |.^ 75 F9        |\JNZ SHORT 00434170
00434177  |.  2BC2          |SUB EAX,EDX                                    ; EAX = strlen()
00434179  |.  8BC8          |MOV ECX,EAX                                    ; blackLengthECX = blackLengthEAX,比较次数
0043417B  |.  8BF5          |MOV ESI,EBP                                    ; pszchESI = pszchEBP
0043417D  |.  33C0          |XOR EAX,EAX
0043417F  |.  F3:A6        |REPE CMPS BYTE PTR DS:[ESI],BYTE PTR ES:[EDI]
00434181  |.  74 65        |JE SHORT 004341E8                              ; 黑名单直接返回FALSE
00434183  |.  83C3 04      |ADD EBX,4
00434186  |.  81FB 80000000 |CMP EBX,80
0043418C  |.^ 72 D4        \JB SHORT 00434162
0043418E  |.  807D 04 73    CMP BYTE PTR SS:[EBP+4],73                      ; Code的第5字节,和's'比较
00434192  |.  75 01        JNE SHORT 00434195
00434194  |.  45            INC EBP
00434195  |>  8D4D 07      LEA ECX,[EBP+7]                                  ; pszchECX = pszchCode + 7或8
00434198  |.  51            PUSH ECX
00434199  |.  E8 56BE0300  CALL 0046FFF4
0043419E  |.  8B5C24 18    MOV EBX,DWORD PTR SS:[ARG.1]                    ; pszchNameEBX指向Name
004341A2  |.  8A13          MOV DL,BYTE PTR DS:[EBX]                        ; EDX_DL = *pszchNameEBX
004341A4  |.  83C4 04      ADD ESP,4
004341A7  |.  33C9          XOR ECX,ECX
004341A9  |.  84D2          TEST DL,DL                                      ; 判断是否空串
004341AB  |.  8BFB          MOV EDI,EBX                                      ; pszchCodeEDI = pszchCodeEBX
004341AD  |.  BE DF0B0000  MOV ESI,0BDF                                    ; ESI = 0BDF=3039
004341B2  |.  74 26        JZ SHORT 004341DA                                ;
004341B4  |>  0FBED2        /MOVSX EDX,DL
004341B7  |.  41            |INC ECX
004341B8  |.  0FAFD1        |IMUL EDX,ECX
004341BB  |.  03F2          |ADD ESI,EDX                                    ; ESI += *pszchEDI * ECX
004341BD  |.  81FE BE170000 |CMP ESI,17BE
004341C3  |.  7E 06        |JLE SHORT 004341CB
004341C5  |.  81EE BE170000 |SUB ESI,17BE                                    ; ESI += *pszchEDI * ECX - 6078.
004341CB  |>  83F9 0A      |CMP ECX,0A
004341CE  |.  7E 02        |JLE SHORT 004341D2
004341D0  |.  33C9          |XOR ECX,ECX
004341D2  |>  8A57 01      |MOV DL,BYTE PTR DS:[EDI+1]
004341D5  |.  47            |INC EDI
004341D6  |.  84D2          |TEST DL,DL
004341D8  |.^ 75 DA        \JNZ SHORT 004341B4
004341DA  |>  3BF0          CMP ESI,EAX
004341DC  |.  75 15        JNE SHORT 004341F3
004341DE  |.  5F            POP EDI
004341DF  |.  5E            POP ESI
004341E0  |.  5D            POP EBP
004341E1  |.  B8 01000000  MOV EAX,1
004341E6  |.  5B            POP EBX
004341E7  |.  C3            RETN
004341E8  |>  5F            POP EDI
004341E9  |.  5E            POP ESI
004341EA  |.  5D            POP EBP
004341EB  |.  33C0          XOR EAX,EAX
004341ED  |.  5B            POP EBX
004341EE  |.  C3            RETN
004341EF  |>  8B5C24 14    MOV EBX,DWORD PTR SS:[ARG.1]                    ; EBX指向Name,ASCII "Fang"
004341F3  |>  55            PUSH EBP
004341F4  |.  53            PUSH EBX
004341F5  |.  E8 16FCFFFF  CALL 00433E10
004341FA  |.  83C4 08      ADD ESP,8
004341FD  |.  5F            POP EDI
004341FE  |.  5E            POP ESI
004341FF  |.  5D            POP EBP
00434200  |.  5B            POP EBX
00434201  \.  C3            RETN

3.3. 第二种注册码生成过程,直接比较Code == Func(Name)形式,这是最初级方式,容易点。
EBP = EDX
= ((EAX + (1 - pszHKRWQ) -1) * (EAX + (1 - pszHKRWQ)) + EBP) % strlen(pszHKRWQ)
= ((EAX - pszHKRWQ) * (EAX - pszHKRWQ + 1) +EBP) % 28
= (indexOf(pszHKRWQ, pszOkName[i]) * (indexOf(pszHKRWQ, pszOkName[i]) + 1) +EBP) % 28

代码:

CPU Disasm
地址        十六进制数据            指令                                              注释
00433E10  /$  8B4424 04    MOV EAX,DWORD PTR SS:[ARG.1]
00433E14  |.  8D9424 38FFFF LEA EDX,[LOCAL.49]
00433E1B  |.  81EC D8000000 SUB ESP,0D8                                      ; 0D8=216.分配空间
00433E21  |.  2BD0          SUB EDX,EAX
00433E23  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]                        ; 拷贝Name倒Local.49缓冲区
00433E25  |.  880C02        |MOV BYTE PTR DS:[EAX+EDX],CL
00433E28  |.  40            |INC EAX
00433E29  |.  84C9          |TEST CL,CL
00433E2B  |.^ 75 F6        \JNZ SHORT 00433E23
00433E2D  |.  53            PUSH EBX
00433E2E  |.  55            PUSH EBP
00433E2F  |.  56            PUSH ESI
00433E30  |.  57            PUSH EDI
00433E31  |.  8D4424 20    LEA EAX,[LOCAL.49]
00433E35  |.  50            PUSH EAX                                        ; /String => OFFSET LOCAL.49
00433E36  |.  FF15 1CF34700 CALL DWORD PTR DS:[<&USER32.CharUpperA>]        ; \USER32.CharUpperA
00433E3C  |.  8A4424 20    MOV AL,BYTE PTR SS:[LOCAL.49]                    ; Local.49里全是大写了
00433E40  |.  84C0          TEST AL,AL                                      ; 判断Local.49是否为空串
00433E42  |.  8D7424 20    LEA ESI,[LOCAL.49]
00433E46  |.  8D7C24 20    LEA EDI,[LOCAL.49]
00433E4A  |.  74 26        JZ SHORT 00433E72
00433E4C  |.  8D6424 00    LEA ESP,[LOCAL.57]                              ; Name里在"HKRWQV2958DWNTQRGNSCFSXAZPYK"的字符拷贝到pszEDIBuffer里,既写回LOCAL.49缓冲区
00433E50  |>  0FBE0E        /MOVSX ECX,BYTE PTR DS:[ESI]                    ; char chECX = *pszESI
00433E53  |.  51            |PUSH ECX
00433E54  |.  68 78F44800  |PUSH OFFSET 0048F478                            ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"
00433E59  |.  E8 E2C10300  |CALL 00470040                                  ; 查找字符
00433E5E  |.  83C4 08      |ADD ESP,8
00433E61  |.  85C0          |TEST EAX,EAX                                    ; 判断是否找到,返回值非空为找到
00433E63  |.  74 05        |JZ SHORT 00433E6A
00433E65  |.  8A16          |MOV DL,BYTE PTR DS:[ESI]                        ; char chDL = *pszESI
00433E67  |.  8817          |MOV BYTE PTR DS:[EDI],DL                        ; *pszEDI = chDL
00433E69  |.  47            |INC EDI                                        ; pszEDI++
00433E6A  |>  8A46 01      |MOV AL,BYTE PTR DS:[ESI+1]                      ; char chAL = *(pszESI+1)
00433E6D  |.  46            |INC ESI                                        ; pszESI++
00433E6E  |.  84C0          |TEST AL,AL
00433E70  |.^ 75 DE        \JNZ SHORT 00433E50                              ; while(0! = chAL)
00433E72  |>  8D4424 20    LEA EAX,[LOCAL.49]
00433E76  |.  C607 00      MOV BYTE PTR DS:[EDI],0                          ; LOCAL.49弄成0结尾字符串
00433E79  |.  8D50 01      LEA EDX,[EAX+1]                                  ; 获取LOCAL.49长度,开始
00433E7C  |.  8D6424 00    LEA ESP,[LOCAL.57]
00433E80  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]
00433E82  |.  40            |INC EAX
00433E83  |.  84C9          |TEST CL,CL
00433E85  |.^ 75 F9        \JNZ SHORT 00433E80
00433E87  |.  2BC2          SUB EAX,EDX                                      ; 获取LOCAL.49长度,结束,EAX=EAX-EDX
00433E89  |.  83F8 18      CMP EAX,18                                      ; 名字长度和18=24.比较
00433E8C  |.  7D 1E        JGE SHORT 00433EAC                              ; 大于0x18=24.就跳转
00433E8E  |.  B9 18000000  MOV ECX,18
00433E93  |.  2BC8          SUB ECX,EAX                                      ; ECX=ECX-EAX=24.-NameLength_EAX
00433E95  |.  8D7C04 20    LEA EDI,[EAX+ESP+20]
00433E99  |.  8BC1          MOV EAX,ECX
00433E9B  |.  C1E9 02      SHR ECX,2
00433E9E  |.  BE 78F44800  MOV ESI,OFFSET 0048F478                          ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"
00433EA3  |.  F3:A5        REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]  ; strcat(LOCAL.49, strchr("HKRW...", LOCAL.49[0]))
00433EA5  |.  8BC8          MOV ECX,EAX
00433EA7  |.  83E1 03      AND ECX,00000003
00433EAA  |.  F3:A4        REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00433EAC  |>  B8 78F44800  MOV EAX,OFFSET 0048F478                          ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"
00433EB1  |.  C64424 39 00  MOV BYTE PTR SS:[LOCAL.43+1],0
00433EB6  |.  C68424 840000 MOV BYTE PTR SS:[LOCAL.24],0
00433EBE  |.  33ED          XOR EBP,EBP                                      ; EBP = 0
00433EC0  |.  8D48 01      LEA ECX,[EAX+1]                                  ; 计算"HKRWQV2958DWNTQRGNSCFSXAZPYK"长度
00433EC3  |>  8A10          /MOV DL,BYTE PTR DS:[EAX]
00433EC5  |.  40            |INC EAX
00433EC6  |.  84D2          |TEST DL,DL
00433EC8  |.^ 75 F9        \JNZ SHORT 00433EC3
00433ECA  |.  2BC1          SUB EAX,ECX                                      ; 计算"HKRWQV2958DWNTQRGNSCFSXAZPYK"结束
00433ECC  |.  894424 10    MOV DWORD PTR SS:[LOCAL.53],EAX                  ; LOCAL53 = 长度24
00433ED0  |.  B8 01000000  MOV EAX,1
00433ED5  |.  2D 78F44800  SUB EAX,OFFSET 0048F478                          ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"
00433EDA  |.  894424 18    MOV DWORD PTR SS:[LOCAL.51],EAX                  ; LOCAL51 = 1 - 0048F478 = FFB70B89
00433EDE  |.  33DB          XOR EBX,EBX                                      ; EBX = 0
00433EE0  |.  B8 78F44800  MOV EAX,OFFSET 0048F478                          ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"
00433EE5  |.  48            DEC EAX                                          ; EAX = 0048F478-1=0048F477
00433EE6  |.  894424 14    MOV DWORD PTR SS:[LOCAL.52],EAX                  ; LOCAL52 = 0048F477
00433EEA  |.  8D4424 20    LEA EAX,[LOCAL.49]                              ; pszchEAX = pszchOkName
00433EEE  |.  48            DEC EAX                                          ; pszchEAX--
00433EEF  |.  8DBC24 840000 LEA EDI,[LOCAL.24]
00433EF6  |.  894424 1C    MOV DWORD PTR SS:[LOCAL.50],EAX                  ; pszchLOCAL50 = pszchEAX = pszchOkName - 1
00433EFA  |.  EB 04        JMP SHORT 00433F00
00433EFC  |>  8B4424 1C    /MOV EAX,DWORD PTR SS:[LOCAL.50]
00433F00  |>  0FBE4C18 01  |MOVSX ECX,BYTE PTR DS:[EBX+EAX+1]              ; pszchECX = pszchOkName[EBX + 1]
00433F05  |.  8D73 01      |LEA ESI,[EBX+1]                                ; ESI = EBX + 1
00433F08  |.  51            |PUSH ECX
00433F09  |.  68 78F44800  |PUSH OFFSET 0048F478                            ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"
00433F0E  |.  E8 2DC10300  |CALL 00470040
00433F13  |.  8B5424 20    |MOV EDX,DWORD PTR SS:[LOCAL.51]                ; EDX = FFB70B89
00433F17  |.  8BC8          |MOV ECX,EAX
00433F19  |.  03CA          |ADD ECX,EDX                                    ; ECX = EAX + FFB70B89
00433F1B  |.  8D41 FF      |LEA EAX,[ECX-1]                                ; EAX = EAX + FFB70B89 - 1
00433F1E  |.  0FAFC1        |IMUL EAX,ECX                                    ; EAX = (ECX - 1) * ECX = FFB70B88 * ECX
00433F21  |.  03C5          |ADD EAX,EBP                                    ; EAX = EAX + EBP
00433F23  |.  99            |CDQ                                            ; 双字数据扩展为四字类型 EDX = EAX < 80000000 ? 00000000 : FFFFFFFF
00433F24  |.  F77C24 18    |IDIV DWORD PTR SS:[LOCAL.53]                    ; 商=(EAX)=(EDX,EAX)/(LOCAL53)(长度),余数=(EDX)=(EDX,EAX)%(LOCAL53)(长度)
00433F28  |.  83C4 08      |ADD ESP,8
00433F2B  |.  B9 06000000  |MOV ECX,6
00433F30  |.  42            |INC EDX
00433F31  |.  8BEA          |MOV EBP,EDX                                    ; EBP = EDX = ((EAX + (1 - pszHKRWQ) -1) * (EAX + (1 - pszHKRWQ)) + EBP) % strlen(pszHKRWQ)
00433F33  |.  8B5424 14    |MOV EDX,DWORD PTR SS:[LOCAL.52]
00433F37  |.  8A042A        |MOV AL,BYTE PTR DS:[EBP+EDX]                    ; AL = pszHKRWQ[EBP]
00433F3A  |.  8807          |MOV BYTE PTR DS:[EDI],AL                        ; *pszchEDI = AL = pszHKRWQ[EBP]
00433F3C  |.  8BC6          |MOV EAX,ESI
00433F3E  |.  99            |CDQ
00433F3F  |.  F7F9          |IDIV ECX
00433F41  |.  47            |INC EDI
00433F42  |.  85D2          |TEST EDX,EDX
00433F44  |.  75 09        |JNZ SHORT 00433F4F
00433F46  |.  83FB 17      |CMP EBX,17                                      ; EBC 和 17=23.比较
00433F49  |.  7D 04        |JGE SHORT 00433F4F
00433F4B  |.  C607 2D      |MOV BYTE PTR DS:[EDI],2D                        ; *pszchEDI = '-'
00433F4E  |.  47            |INC EDI
00433F4F  |>  8BDE          |MOV EBX,ESI
00433F51  |.  83FB 18      |CMP EBX,18                                      ; 和长度18=24.比较
00433F54  |.^ 7C A6        \JL SHORT 00433EFC                              ; 小于继续循环,否则结束循环
00433F56  |.  8B8424 F00000 MOV EAX,DWORD PTR SS:[ARG.2]                    ; pszEAX = pszCode
00433F5D  |.  C607 00      MOV BYTE PTR DS:[EDI],0
00433F60  |.  8DB424 840000 LEA ESI,[LOCAL.24]                              ; pszESI=pszRealCode; 一段序列,如HSDWQ9-QKFADW-H92C5A-GAGVNK
00433F67  |>  8A10          /MOV DL,BYTE PTR DS:[EAX]
00433F69  |.  8A1E          |MOV BL,BYTE PTR DS:[ESI]
00433F6B  |.  8ACA          |MOV CL,DL
00433F6D  |.  3AD3          |CMP DL,BL
00433F6F  |.  75 1E        |JNE SHORT 00433F8F
00433F71  |.  84C9          |TEST CL,CL
00433F73  |.  74 16        |JZ SHORT 00433F8B
00433F75  |.  8A50 01      |MOV DL,BYTE PTR DS:[EAX+1]
00433F78  |.  8A5E 01      |MOV BL,BYTE PTR DS:[ESI+1]
00433F7B  |.  8ACA          |MOV CL,DL
00433F7D  |.  3AD3          |CMP DL,BL
00433F7F  |.  75 0E        |JNE SHORT 00433F8F
00433F81  |.  83C0 02      |ADD EAX,2
00433F84  |.  83C6 02      |ADD ESI,2
00433F87  |.  84C9          |TEST CL,CL
00433F89  |.^ 75 DC        \JNZ SHORT 00433F67
00433F8B  |>  33C0          XOR EAX,EAX
00433F8D  |.  EB 05        JMP SHORT 00433F94
00433F8F  |>  1BC0          SBB EAX,EAX                                      ; Calculates sign(EAX)
00433F91  |.  83D8 FF      SBB EAX,-1
00433F94  |>  85C0          TEST EAX,EAX
00433F96  |.  5F            POP EDI
00433F97  |.  5E            POP ESI
00433F98  |.  5D            POP EBP
00433F99  |.  5B            POP EBX
00433F9A  |.  75 0C        JNZ SHORT 00433FA8                              ; Code和Func(Name)的值不等,就跳,返回假
00433F9C  |.  B8 01000000  MOV EAX,1
00433FA1  |.  81C4 D8000000 ADD ESP,0D8
00433FA7  |.  C3            RETN
00433FA8  |>  33C0          XOR EAX,EAX
00433FAA  |.  81C4 D8000000 ADD ESP,0D8
00433FB0  \.  C3            RETN

字符串比较指令(Compare String Instruction)
该指令是把指针DS:SI和ES:DI所指向字节、字或双字的值相减,并用所得到的差来设置有关的标志位。与此同时,变址寄存器SI和DI也将根据标志位DF的值作相应增减。
指令的格式:CMPS 地址表达式1, 地址表达式2
CMPSB/CMPSW
CMPSD      ;80386+
受影响的标志位:AF、CF、OF、PF、SF和ZF

5. 注册代码

5.1. Javascript
代码:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>GIFMovieGear KeyGen</title>
    <style type="text/css">
        p {
            font-family: 'Lucida Console', Monaco, monospace;
        }

        button {
            width: 150px;
        }

        .bg {
            font-style: italic;
            color: gray;
        }
    </style>
    <script language="javascript" type="text/javascript">
        //Fang = HSDWQ9-QKFADW-H92C5A-GAGVNK  CB D5 B1 B1|D0 A1 C2 F3| = 苏北小麦
        function Generate() {
            var inputs = document.getElementsByTagName("input");
            //var addrHKRW = 0x48F478, local51 = 1 - 0x48F478, local52 = 0x48F478 - 1;
            //local51 = 0xFFB70B89;//0xFFFFFFFF - 0x48F478 + 2
            var idx, i, ch;
            var name = inputs[0].value, rName = [], resTab = "HKRWQV2958DWNTQRGNSCFSXAZPYK";
            var letterTable = "0123456789abcdefghijklmnopqrstuvwxyz"
            var ediRCode = [], ebp = 0;//, eax, ecx;
            var codeTypes = document.getElementsByName("codetype");
            //两种注册码,mg37开头的和不是这开头的短横线分割的
            if (!codeTypes[2].checked) {
                do {
                    ediRCode = "mg37";
                    idx = name.length;
                    if (codeTypes[0].checked)
                        ediRCode += 's';
                    ediRCode += randomLetter(letterTable) + randomLetter(letterTable) + randomLetter(letterTable);
                    var esi = 3039, ecx = 0, edx;
                    //每一项0x00 - 0xFF
                    var codes = GB2312CodeArray(name);
                    for (i = 0; i < codes.length; i++) {
                        ++ecx;
                        edx = codes[i];
                        if (edx > 0x7F)
                            edx = -(~(edx - 1) & 0xff);
                        esi += ecx * edx;
                        if (esi > 6078)
                            esi -= 6078;
                        if (ecx > 10)
                            ecx = 0;
                    }
                    ediRCode += esi;
                } while (isBlackCode(ediRCode));
            } else {
                name = name.toUpperCase()
                for (i = 0; i < name.length; i++) {
                    ch = name.charAt(i);
                    idx = resTab.indexOf(ch);
                    if (-1 != idx)//有才压入
                        rName.push(ch);
                }
                //rName每一个字符都存在于resTab中
                rName = rName.join("");
                //不足24位补齐
                if (rName.length < 24)
                    rName = rName + resTab.substring(0, 24 - rName.length);
                i = 0;
                //Code长度为24
                while (i < 24) {
                    idx = resTab.indexOf(rName.charAt(i));
                    //eax = addrHKRW + idx;
                    //ecx = (eax + local51) & 0xFFFFFFFF;//rAdd(eax, local51);
                    //ebp = rAdd(ebp, (ecx - 1)* ecx) % resTab.length;
                    ebp = (idx * (idx + 1) + ebp) % resTab.length;
                    ediRCode.push(resTab.charAt(ebp++));
                    if (!(++i % 6) && i < 24)
                        ediRCode.push('-');
                }
                ediRCode = ediRCode.join("");
            }
            inputs[1].value = ediRCode;
        };

        //模拟32位寄存器值相加
        /*function rAdd(v1, v2){
            var v = v1 + v2;
            if(v > 0xFFFFFFFF)
                v &= 0xFFFFFFFF;
            return v;
        }*/
        var blackCodes = ["mvg21951736", "mg374604342", "mg370534035", "mg373465241", "mg37NTi", "mg372503958", "mg379843149", "mg370151347", "mg370353008", "mg372021424", "mg375953248", "mg379223953", "mg373473759", "mg378542544", "mg370473710", "mg37064348", "mg378822469", "mg374394987", "mg371073478", "mg379773651", "mg371895266", "mg373223554", "mg377583454", "mg37644957", "mg370342692", "mg376484039", "mg376871434", "mg370704788", "mg377643863", "mg377753931", "mg379342689", "mg374344777"];
        function isBlackCode(code) {
            for (i = blackCodes.length; i > 0; i--) {
                if (code == blackCodes[--i]) {
                    return true;
                }
            }
            return false;
        }

        function randomLetter(letterTable) {
            return letterTable.charAt(Math.floor(Math.random() * letterTable.length));
        }

        function codeChange() {
            var testCode = document.getElementsByName("testCode");
            var raw = testCode[0].value;
            var charCodes = [];
            for (var i = 0; i < raw.length; i++) {
                charCodes.push(raw.charCodeAt(i).toString(16));
            }
            testCode[1].value = charCodes.join();
            //
            charCodes.length = 0;
            var encodeArray = encodeURI(raw).split("%");
            for (var i = 1; i < encodeArray.length; i += 3) {
                charCodes.push(encodeArray[i] + encodeArray[i + 1] + encodeArray[i + 2]);
            }
            testCode[2].value = charCodes.join();
            charCodes.length = 0;
            //
            var gb2312Codes = GB2312CodeArray(raw);
            for (var i = 0; i < gb2312Codes.length; i += 2) {
                charCodes.push(gb2312Codes[i].toString(16) + gb2312Codes[i + 1].toString(16));
            }
            testCode[3].value = charCodes.join();
        }

        function init() {
            Generate();
            codeChange();
            var c = document.getElementById("c");
            var ctx = c.getContext("2d");
            c.height = 100;
            c.width = 300;
            var txts = "CRACK".split("");
            var font_size = 12;
            var columns = c.width / font_size;
            var drops = [];
            for (var x = 0; x < columns; x++)
                drops[x] = 1;

            function draw() {
                ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
                ctx.fillRect(0, 0, c.width, c.height);
                ctx.fillStyle = "#0F0";
                ctx.font = font_size + "px arial";
                for (var i = 0; i < drops.length; i++) {
                    var text = txts[Math.floor(Math.random() * txts.length)];
                    ctx.fillText(text, i * font_size, drops[i] * font_size);
                    if (drops[i] * font_size > c.height || Math.random() > 0.8)
                        drops[i] = 0;
                    drops[i]++;
                }
            }

            setInterval(draw, 66);
        }

        /** 返回[] http://blog.csdn.net/yimengqiannian/article/details/7016720  */
        function GB2312CodeArray(str) {
            /*********改自<a href="http://blog.csdn.net/qiushuiwuhen/article/details/14112">qiushuiwuhen(2002-9-16)</a>********/
            var ch, pos, cod, gbkCode = [];
            for (var i = 0; i < str.length; i++) {
                ch = str.charAt(i);
                cod = str.charCodeAt(i);
                //汉字字符
                if (cod >= 0x4e00 && cod < 0x9FA5) {
                    if (-1 != (pos = GBhz.indexOf(ch))) {
                        gbkCode.push(0xB0 + parseInt(pos / 94));
                        gbkCode.push(0xA1 + pos % 94);
                    }
                } else if ((pos = GBfh.indexOf(ch)) != -1) {
                    gbkCode.push(0xA1 + parseInt(pos / 94));
                    gbkCode.push(0xA1 + pos % 94);
                }
                else gbkCode.push(parseInt(cod));
            }
            return gbkCode;
        }
        //采录的只是GB2312编码
        var GBfh = " 、。•ˉˇ¨〃々—~‖…‘’“”〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψω︵︶︹︺︿﹀︽︾﹁﹂﹃﹄︻︼︷︸︱︳︴АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяāáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑńňɡㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋";
        var GBhz = "啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧饨饩饪饫饬饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡缢缣缤缥缦缧缪缫缬缭缯缰缱缲缳缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶钷钸钹钺钼钽钿铄铈铉铊铋铌铍铎铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒锓锔锕锖锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤镥镦镧镨镩镪镫镬镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨鸩鸪鸫鸬鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦鹧鹨鹩鹪鹫鹬鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅龆龇龈龉龊龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞鲟鲠鲡鲢鲣鲥鲦鲧鲨鲩鲫鲭鲮鲰鲱鲲鲳鲴鲵鲶鲷鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋鳌鳍鳎鳏鳐鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄";

    </script>
</head>
<body onload="init()">
    <canvas id="c"></canvas><br>
    <p>Name:<input value="Fang" size="36" /></p>
    <p>Code:<input size="36" readonly="true" /></p>
    <p>
        <input type="radio" name="codetype" checked="checked" />Site License<br>
        <input type="radio" name="codetype" />Register Code N<br>
        <input type="radio" name="codetype" />Register Code A
    </p>
    <p><button onclick="Generate()">Generate</button><button onclick="window.close();">Close</button></p>
    <p>
        <span class="bg">"HKRWQV2958DWNTQRGNSCFSXAZPYK"</span><br>
        <span class="bg">[Provided by Fang3s]</span>
    </p>
    <table>
        <tr><td>Input Here:</td><td><input name="testCode" onchange="codeChange()" value="苏北小麦" size="36" /></td></tr>
        <tr><td>charCodeAt:</td><td><input name="testCode" value="" size="36" /></td></tr>
        <tr><td>encodeURI:</td><td><input name="testCode" value="" size="36" /></td></tr>
        <tr><td>GB2312:</td><td><input name="testCode" value="" size="36" /></td></tr>
    </table>
</body>
</html>

C++
代码:

const char *psBlackCodes[] = { "mvg21951736", "mg374604342", "mg370534035", "mg373465241", "mg37NTi", "mg372503958", "mg379843149",
"mg370151347", "mg370353008", "mg372021424", "mg375953248", "mg379223953", "mg373473759", "mg378542544", "mg370473710", "mg37064348",
"mg378822469", "mg374394987", "mg371073478", "mg379773651", "mg371895266", "mg373223554", "mg377583454", "mg37644957", "mg370342692",
"mg376484039", "mg376871434", "mg370704788", "mg377643863", "mg377753931", "mg379342689", "mg374344777" };
const char* pszRandomCharTable = "0123456789abcdefghijklmnopqrstuvwxyz";
const int lengthOfCharTable = lstrlenA(pszRandomCharTable);
const char *pResourceTable = "HKRWQV2958DWNTQRGNSCFSXAZPYK";


inline char randomChar(void){
        return pszRandomCharTable[rand() % (lengthOfCharTable + 1 - 0) + 0];
}

如果dump代码,怎么搞都没搞成,不用ebp的。。
代码:

//see http://msdn.microsoft.com/zh-cn/library/chh3fb0k(v=vs.80).aspx  http://msdn.microsoft.com/zh-cn/library/2kxx5t2c(VS.80).aspx
//#pragma optimize( "y", off )  // 对下面的代码使用  /Oy 优化 Generate frame pointers on the program stack.
int keygen_dump(const char *arg_0, const char *arg_4){
        //框架指针寄存器“ebp”被内联程序集代码修改

        _asm{
                mov    ebp, arg_4        //就乱了。。。。
                cmp    byte ptr[ebp + 0], 6Dh
                jnz    loc_4341EF
                cmp    byte ptr[ebp + 1], 67h
                jnz    loc_4341EF
                cmp    byte ptr[ebp + 2], 33h
                jnz    loc_4341EF
                cmp    byte ptr[ebp + 3], 37h
                jnz    loc_4341EF
                xor    ebx, ebx

        loc_434162 :
                mov    edi, psBlackCodes
                mov    eax, edi
                lea    edx, [eax + 1]
                lea    ecx, [ecx + 0]

        loc_434170 :
                          mov    cl, [eax]
                          inc    eax
                          test    cl, cl
                          jnz    short loc_434170
                          sub    eax, edx
                          mov    ecx, eax
                          mov    esi, ebp
                          xor    eax, eax
                          repe cmpsb
                          jz      short loc_4341E8
                          add    ebx, 4
                          cmp    ebx, 80h
                          jb      short loc_434162
                          cmp    byte ptr[ebp + 4], 73h
                          jnz    short loc_434195
                          inc    ebp

                  loc_434195 :
        lea    ecx, [ebp + 7]
                push    ecx
                push        ecx
                call    codekeygen  //----------------------------------
                pop ecx
                pop ecx
                push    ecx
                call    atol
                mov    ebx, arg_0
                mov    dl, [ebx]
                add    esp, 4
                xor    ecx, ecx
                test    dl, dl
                mov    edi, ebx
                mov    esi, 0BDFh
                jz      short loc_4341DA

        loc_4341B4 :
        movsx  edx, dl
                inc    ecx
                imul    edx, ecx
                add    esi, edx
                cmp    esi, 17BEh
                jle    short loc_4341CB
                sub    esi, 17BEh

        loc_4341CB:
        cmp    ecx, 0Ah
                jle    short loc_4341D2
                xor    ecx, ecx

        loc_4341D2 :
        mov    dl, [edi + 1]
                inc    edi
                test    dl, dl
                jnz    short loc_4341B4

        loc_4341DA :
        push esi

        cmp    esi, eax

                jnz    short loc_4341F3
                pop    ebp
                mov    eax, 1
                pop    ebx
                retn//移除pop esi和pop ebp


        loc_4341E8 :
        pop    edi

                xor    eax, eax
                pop    ebx
                retn //移除pop esi和pop ebp


        loc_4341EF :

        mov    ebx,  arg_0

        loc_4341F3 :
        push    ebp
                push    ebx
                call    codekeygen  //移除两参数
                          pop    ebp
                          pop    ebx
                          retn//移除pop esi和pop ebp
}
}
//#pragma optimize("", on)    // 恢复到编译器 /O 选项指定的优化

5.3. 汇编(跃然纸上)
注册时让注册码跃然纸上,这招貌似叫内嵌补丁。
个人觉得算是个费时的活儿,又写汇编,又要了解PE等,知识点散。而且只适用于程序把注册码计算出来和输入的Code直接比较,即Code == Func(Name)???型。避免了写注册机算法等等,如果很复杂这很适合,当然也可以远程调用。
为了便于好看,有大量截图,也是用心写的证明,就想发点有价值的东西,不然不好。

5.3.1. 第一处改写。
主要获取Code窗口句柄HWND和保存,如果是局部变量就好了,但是我没看看它是不是,直接保存到代码区的。
修改前两处
附件 92062
修改前后
附件 92063
5.3.2. 目标代码。

来到我们预定的空隙处,这里也是准备些代码的地方,这里call api暂时是拷贝的,后面修改。
附件 92064
设置访问方式
附件 92065

修改访问后,再执行此条指令,如下图我们看到地址0x0047EA94值变了,共4字节。注意这里是临时修改,要实际修改,还要保存。君子善假于物也。使用论坛工具LordPE。

附件 92066
附件 92067

继续执行到原来PUSH EAX后的指令CALL EBX时,即此处的寄存器状态和之前未修改的图是一致的。这里要说下,原来未修改的截图还未执行PUSH EAX,所以原ESP比这里的大4,截得不好。

5.3.3. 第二处改写

来到注册码已经出来的地方,然后我们想在界面Code编辑框里打印显示出来。
说明下,由于ESP寻找局部变量,所以只要找到ESP+84(十六进制)处看看就可,右下角堆栈窗口就可以看;或者直接点击代码行右键-数据窗口中跟随-内存地址,即可左小角查看。
这条指令大于5字节,直接线程替换为我们的跳转JMP 0047EA9E,剩余的90填充然后F7或F8跟随进去。

附件 92069
附件 92068

当我们获取原来LEA ESI, [LOCAL.24]里的[LOCAL.24]=[ESP + 84]时,堆栈和原来不一样的差了8.*4 = 32. = 20h,从右下角的图也可以看出,当时记录的ESP和此时ESP相差$-20。所以取值时多加了这个差值。

附件 92070

我们走一步,通过赋值给ESI看下这时的值,OllyDbg会提示的。

附件 92071

再看看第一个入参,[Alt+W]打开当前可预见的窗口。

附件 92072

5.3.4. 这里call API有一定讲究。

导入API

首先看它导入了没有,OK。
OllyDbg的查找所有模块中的名称(Ctrl+N)

附件 92073
附件 92074

call地址计算

目标进程右键-载入PE编辑器-目录-输入表一行左边省略号按钮上面ListView点选USER32.dll-下面输入SetWindowTextA搜索自动定位。
注意未勾选总是查看FisrtThunk时值时,ThunkRVA按照函数列表计算的值是不一样的。

附件 92075

未勾选时,第一个函数SystemParametersInfoA的ThunkRVA是0008BCC8和USER32.dll的OrigianlFirstThunk一样的,以后相差+4。

附件 92076

勾选后,地址为0007F30C,记下它,后面会眼熟的。

附件 92077

我们来拿个现成例子看看地址间关系。
回到OllyDbg,在程序模块movgear.exe,右键查找-所有模块间调用

附件 92078

搜索System看到

附件 92079

点击进入

附件 92080

我们看看SystemParametersInfoA的调用方式不是CALL xx,而是CALL DWORD PTR DS:[xx],即call机器码不一样。
再看看地址关系,可以看出CALL DWORD PTR DS:[xx]的xx是0047F30C,后4位是不是很眼熟。是的,和前面看到的ThunkRVA = 0047F30C,是一致的,只是多了个400000,其实40万(十六进制)就是我们在前面一起看到的,基本PE头信息里的镜像基址(BaseImage)400000。
接下来看我们的SetWindowTextA,以此类推,调用写法,400000 + 0007F448 = 0047F448 ,48F44700,CALL DWORD PTR DS:[ 0047F448],OllyDbg自动解析为对应符号。

附件 92081

5.3.5. 修改的代码

代码:

CPU Disasm
地址        十六进制数据            指令                                      注释
00434531    /E9 68A50400  JMP 0047EA9E
 

CPU Disasm
地址        十六进制数据            指令                                      注释
00433F60    /E9 39AB0400  JMP 0047EA9E
 

CPU Disasm
地址        十六进制数据            指令                                      注释
0047EA97      00            DB 00                                    ; 原来.text区是不可写,这也证明了足够
0047EA98      00            DB 00                                    ; 安全性,而且原是0映射后还是0,
0047EA99      00            DB 00                                    ; 不用搞检测看这段是否可能被修改。
0047EA9A      00            DB 00                                    ; 一般程序也不会调用API来改吧,又没壳。
0047EA9B      00            DB 00
0047EA9C      00            DB 00
0047EA9D      00            DB 00
0047EA9E  />  60            PUSHAD                                  ; /Arg1_4, >>保存8大寄存器状态,也可仅push使用的
0047EA9F  |.  E8 00000000  CALL 0047EAA4                            ; \movgear.0047EAA4, 随意搞吧,不管你怎么使用寄存器,只要栈操作平衡。
0047EAA4  |$  59            POP ECX                                  ; 获取EIP,即ECX = EIP = 0047EAA4
0047EAA5  |.  8B51 F0      MOV EDX,DWORD PTR DS:[ECX-10]            ; 这里把.text区地址0047EA94上DWORD大小给了EDX
0047EAA8  |.  85D2          TEST EDX,EDX
0047EAAA  |.  75 12        JNZ SHORT 0047EABE
0047EAAC  |.  8941 F0      MOV DWORD PTR DS:[ECX-10],EAX
0047EAAF  |.  61            POPAD                                    ; <<恢复8大寄存器状态
0047EAB0  |.  FFD3          CALL EBX                                ; >>恢复原指令的调用流程
0047EAB2  |.  8D8CE4 C40000 LEA ECX,[LOCAL.24]                      ; <<恢复原指令的调用流程
0047EAB9  |.^ E9 7C5AFBFF  JMP 0043453A                            ; 回去并执行接下来的指令
0047EABE  |>  C741 F0 00000 MOV DWORD PTR DS:[ECX-10],0
0047EAC5  |.  8DB4E4 A40000 LEA ESI,[LOCAL.24]                      ; 这里使用ESP的局部变量要注意。
0047EACC  |.  56            PUSH ESI                                ; /Text
0047EACD  |.  52            PUSH EDX                                ; |hWnd
0047EACE  |.  FF15 48F44700 CALL DWORD PTR DS:[<&USER32.SetWindowTex ; \USER32.SetWindowTextA, call xx 需要计算xx = ImageBase + ThunkRVAOfAPI
0047EAD4  |.  61            POPAD                                    ; <<恢复8大寄存器状态
0047EAD5  |.  8DB4E4 840000 LEA ESI,[LOCAL.24]                      ; >><<恢复原指令的调用流程
0047EADC  \.^ E9 8654FBFF  JMP 00433F67                            ; 回去并执行接下来的指令
0047EAE1      E8 6B25EB74  CALL SetWindowTextA                        ;直接修改为CALL SetWindowTextA,错,仅临时偏移对

5.3.6. 最后看下效果图:
附件 92083

6. 总结

LoadPE使用,熟练OllyDbg,Call API
7. 附件
GIF Movie Gear破解记录(含程序) 附件 92119

上传的图像
文件类型: jpg image001.jpg (46.8 KB)
文件类型: png image002.png (141.8 KB)
文件类型: png image003.png (13.5 KB)
文件类型: png image004.png (15.5 KB)
文件类型: png image005.png (36.9 KB)
文件类型: png image006.png (87.8 KB)
文件类型: png image007.png (80.4 KB)
文件类型: png image008.png (49.8 KB)
文件类型: png image009.png (28.5 KB)
文件类型: png image010.png (36.1 KB)
文件类型: png image011.png (70.4 KB)
文件类型: png image012.png (40.8 KB)
文件类型: png image013.png (56.5 KB)
文件类型: png image014.png (59.0 KB)
文件类型: png image015.png (59.1 KB)
文件类型: png image016.png (59.6 KB)
文件类型: png image017.png (68.9 KB)
文件类型: png image018.png (59.0 KB)
文件类型: png image019.png (2.5 KB)
文件类型: png image020.png (74.2 KB)
文件类型: png image021.png (72.5 KB)
文件类型: png image022.png (70.0 KB)
文件类型: png image023.png (92.2 KB)
文件类型: png image024.png (3.5 KB)
文件类型: png image025.png (69.8 KB)
文件类型: png image026.png (85.6 KB)
文件类型: png image027.png (15.7 KB)
文件类型: png image028.png (15.7 KB)
文件类型: png image029.png (126.8 KB)
文件类型: png image030.png (102.2 KB)
文件类型: png image031.png (10.8 KB)
文件类型: png image032.png (16.1 KB)
文件类型: png image035.png (10.6 KB)
文件类型: gif movgear_crack.gif (19.6 KB)
文件类型: png image001.png (48.1 KB)
上传的附件
文件类型: doc GIF Movie Gear破解记录(含程序).doc (2.96 MB)

【原创】Acid burn 算法注册机

$
0
0
【破解作者】 Night
【作者主页】 www.freecracker.com
【使用工具】 OD
【破解平台】 Win7
【软件名称】 附件 92122
------------------------------------------------------------------------------------------------------------
0042F998 /. 55 push ebp
0042F999 |. 8BEC mov ebp,esp
0042F99B |. 33C9 xor ecx,ecx
0042F99D |. 51 push ecx
0042F99E |. 51 push ecx
0042F99F |. 51 push ecx
0042F9A0 |. 51 push ecx
0042F9A1 |. 51 push ecx
0042F9A2 |. 51 push ecx
0042F9A3 |. 53 push ebx
0042F9A4 |. 56 push esi
0042F9A5 |. 8BD8 mov ebx,eax
0042F9A7 |. 33C0 xor eax,eax
0042F9A9 |. 55 push ebp
0042F9AA |. 68 67FB4200 push path_gay.0042FB67
0042F9AF |. 64:FF30 push dword ptr fs:[eax]
0042F9B2 |. 64:8920 mov dword ptr fs:[eax],esp
0042F9B5 |. C705 50174300>mov dword ptr ds:[0x431750],0x29
0042F9BF |. 8D55 F0 lea edx,[local.4]
0042F9C2 |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042F9C8 |. E8 8BB0FEFF call path_gay.0041AA58
0042F9CD |. 8B45 F0 mov eax,[local.4] ; 获取用户名
0042F9D0 |. E8 DB40FDFF call path_gay.00403AB0 ; 判断用户名不能为空
0042F9D5 |. A3 6C174300 mov dword ptr ds:[0x43176C],eax
0042F9DA |. 8D55 F0 lea edx,[local.4]
0042F9DD |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042F9E3 |. E8 70B0FEFF call path_gay.0041AA58
0042F9E8 |. 8B45 F0 mov eax,[local.4] ; 获取用户名
0042F9EB |. 0FB600 movzx eax,byte ptr ds:[eax] ; 用户名的第一位放入到eax中
0042F9EE |. 8BF0 mov esi,eax ; 用户名的第一位 放入到esi 中
0042F9F0 |. C1E6 03 shl esi,0x3 ; esi = esi << 3
0042F9F3 |. 2BF0 sub esi,eax ; esi = esi - eax
0042F9F5 |. 8D55 EC lea edx,[local.5]
0042F9F8 |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042F9FE |. E8 55B0FEFF call path_gay.0041AA58 ; 返回用户名长度
0042FA03 |. 8B45 EC mov eax,[local.5]
0042FA06 |. 0FB640 01 movzx eax,byte ptr ds:[eax+0x1] ; 用户名的第二位保存到eax中
0042FA0A |. C1E0 04 shl eax,0x4 ; eax = eax << 4
0042FA0D |. 03F0 add esi,eax ; esi = esi + eax
0042FA0F |. 8935 54174300 mov dword ptr ds:[0x431754],esi ; ds:[0x431754] = 8B2
0042FA15 |. 8D55 F0 lea edx,[local.4]
0042FA18 |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042FA1E |. E8 35B0FEFF call path_gay.0041AA58 ; 返回用户名长度
0042FA23 |. 8B45 F0 mov eax,[local.4]
0042FA26 |. 0FB640 03 movzx eax,byte ptr ds:[eax+0x3] ; 用户名第四位保存到eax中
0042FA2A |. 6BF0 0B imul esi,eax,0xB ; esi = eax * 0xB
0042FA2D |. 8D55 EC lea edx,[local.5]
0042FA30 |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042FA36 |. E8 1DB0FEFF call path_gay.0041AA58
0042FA3B |. 8B45 EC mov eax,[local.5]
0042FA3E |. 0FB640 02 movzx eax,byte ptr ds:[eax+0x2] ; 用户名第三位保存到 eax 中
0042FA42 |. 6BC0 0E imul eax,eax,0xE ; eax = eax * 0xE
0042FA45 |. 03F0 add esi,eax ; esi = esi + eax
0042FA47 |. 8935 58174300 mov dword ptr ds:[0x431758],esi ; ds:[0x431758] = 0A1A
0042FA4D |. A1 6C174300 mov eax,dword ptr ds:[0x43176C]
0042FA52 |. E8 D96EFDFF call path_gay.00406930
0042FA57 |. 83F8 04 cmp eax,0x4
0042FA5A |. 7D 1D jge Xpath_gay.0042FA79 ; 用户名必须大于等于四位
0042FA5C |. 6A 00 push 0x0
0042FA5E |. B9 74FB4200 mov ecx,path_gay.0042FB74 ; ASCII 54,"ry Again!"
0042FA63 |. BA 80FB4200 mov edx,path_gay.0042FB80 ; ASCII 53,"orry , The serial is incorect !"
0042FA68 |. A1 480A4300 mov eax,dword ptr ds:[0x430A48]
0042FA6D |. 8B00 mov eax,dword ptr ds:[eax]
0042FA6F |. E8 FCA6FFFF call path_gay.0042A170
0042FA74 |. E9 BE000000 jmp path_gay.0042FB37
0042FA79 |> 8D55 F0 lea edx,[local.4]
0042FA7C |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042FA82 |. E8 D1AFFEFF call path_gay.0041AA58
0042FA87 |. 8B45 F0 mov eax,[local.4]
0042FA8A |. 0FB600 movzx eax,byte ptr ds:[eax] ; 取用户名第一位 保存到 eax 中
0042FA8D |. F72D 50174300 imul dword ptr ds:[0x431750] ; eax = eax * ds:[0x431750]
0042FA93 |. A3 50174300 mov dword ptr ds:[0x431750],eax ; ds:[0x431750] = 0xC7E
0042FA98 |. A1 50174300 mov eax,dword ptr ds:[0x431750]
0042FA9D |. 0105 50174300 add dword ptr ds:[0x431750],eax ; ds:[0x431750] = ds:[0X431750]*2
0042FAA3 |. 8D45 FC lea eax,[local.1]
0042FAA6 |. BA ACFB4200 mov edx,path_gay.0042FBAC
0042FAAB |. E8 583CFDFF call path_gay.00403708
0042FAB0 |. 8D45 F8 lea eax,[local.2]
0042FAB3 |. BA B8FB4200 mov edx,path_gay.0042FBB8
0042FAB8 |. E8 4B3CFDFF call path_gay.00403708
0042FABD |. FF75 FC push [local.1]
0042FAC0 |. 68 C8FB4200 push path_gay.0042FBC8 ; UNICODE "-"
0042FAC5 |. 8D55 E8 lea edx,[local.6]
0042FAC8 |. A1 50174300 mov eax,dword ptr ds:[0x431750]
0042FACD |. E8 466CFDFF call path_gay.00406718 ; 这个函数
0042FAD2 |. FF75 E8 push [local.6]
0042FAD5 |. 68 C8FB4200 push path_gay.0042FBC8 ; UNICODE "-"
0042FADA |. FF75 F8 push [local.2]
0042FADD |. 8D45 F4 lea eax,[local.3]
0042FAE0 |. BA 05000000 mov edx,0x5
0042FAE5 |. E8 C23EFDFF call path_gay.004039AC ; 拼接生成真的Key值
0042FAEA |. 8D55 F0 lea edx,[local.4]
0042FAED |. 8B83 E0010000 mov eax,dword ptr ds:[ebx+0x1E0]
0042FAF3 |. E8 60AFFEFF call path_gay.0041AA58 ; 获取Key值
0042FAF8 |. 8B55 F0 mov edx,[local.4] ; 假的Key值
0042FAFB |. 8B45 F4 mov eax,[local.3] ; 真的Key值
0042FAFE |. E8 F93EFDFF call path_gay.004039FC ; 比较

Key值中间部分计算函数 如下
00406DC2 |$ B9 0A000000 mov ecx,0xA ; ecx = 0xA
00406DC7 |> 8D75 C4 lea esi,[local.15]
00406DCA |> 31D2 /xor edx,edx ; edx 清零
00406DCC |. F7F1 |div ecx ; eax / ecx eax中存放商 edx 中存放余数
00406DCE |. 80C2 30 |add dl,0x30 ; dl = dl + 0x30
00406DD1 |. 80FA 3A |cmp dl,0x3A ; 判断dl 是否 小于 0x3A
00406DD4 |. 72 03 |jb Xpath_gay.00406DD9
00406DD6 |. 80C2 07 |add dl,0x7 ; 如果不小于0x3A 的话 dl = dl + 0x7
00406DD9 |> 4E |dec esi
00406DDA |. 8816 |mov byte ptr ds:[esi],dl ; 保存结果
00406DDC |. 09C0 |or eax,eax
00406DDE |.^ 75 EA \jnz Xpath_gay.00406DCA
00406DE0 |. 8D4D C4 lea ecx,[local.15]
00406DE3 |. 29F1 sub ecx,esi
00406DE5 |. 8B55 E0 mov edx,[local.8]
00406DE8 |. 83FA 10 cmp edx,0x10
00406DEB |. 72 01 jb Xpath_gay.00406DEE
00406DED |. C3 retn


注册机代码如下 :
/***
* Acid burn.exe 程序注册机
* 完成时间: 2014年9月10日 23:43
* 完成人 : Night
*/

#include "stdafx.h"
#include "string.h"

int _tmain(int argc, _TCHAR* argv[])
{
//存放用户名
char userName[100] = {0};
//内存00431750地址处的值
unsigned int value_431750 = 0x29;
//临时存放值
unsigned int value = 0;
//控制数组下标
unsigned int k = 0;
//程序中初始化的值
unsigned int x = 0xA;
//存放商
unsigned int quotient = 0;
//存放余数
unsigned int mod = 0;
//存放结果
unsigned int result[10] = {0};
//把存放的结果转化成字符再倒置
char encode[10] = {0};
//CrackMe程序初始化注册码的前缀
char before [30] = "CW-";
//CrackMe程序初始化注册码的后缀
char after [9] = "-CRACKED";

printf("请输入用户名:");
gets_s(userName);

value = userName[0] * value_431750;
value = value * 2;

do
{
mod = 0;
quotient = value / x ;
mod = value % x ;

mod = mod + 0x30;

if(mod > 0x3A)
{
mod = mod + 0x7;
}
result[k++] = mod ;

value = quotient;
} while (value);

for (int i = 0; i < k; i++)
{
encode[k-i-1] = result[i];
}
strcat_s(before,encode);
strcat_s(before,after);
puts(before);
printf("\n");
return 0;
}

PS: VS2012 编译,如果注册机有问题或者有更简洁的算法 请大神们多多指教。谢谢

上传的附件
文件类型: zip Acid_burn.zip (366.3 KB)

【原创】一道有意思的题

$
0
0
做了这个题目,觉得挺有意思。就在看雪给出writeup和大家交流一下吧!

     附件 92139

     随便输入可以断在下面:
    附件 92140
     单步到这里,看到了刚才输入的pass1:
     附件 92141
     进入函数call 004011D0后找到这里:
    附件 92142 
    
004011A0     8B4C24 08      mov ecx,dword ptr ss:[esp+8]
004011A4     B8 01000000    mov eax,1
004011A9     41             inc ecx
004011AA     3BC8           cmp ecx,eax
004011AC     74 18          je short 4.004011C6
004011AE     56             push esi
004011AF     8B7424 10      mov esi,dword ptr ss:[esp+10]
004011B3     57             push edi
004011B4     8B7C24 0C      mov edi,dword ptr ss:[esp+C]
004011B8     49             dec ecx
004011B9     0FAFC7         imul eax,edi
004011BC     99             cdq
004011BD     F7FE           idiv esi
004011BF     49             dec ecx
004011C0     8BC2           mov eax,edx
004011C2   ^ 75 F5          jnz short 4.004011B9
004011C4     5F             pop edi
004011C5     5E             pop esi
004011C6     C3             retn
这段代码就是一次取出422000开始处的2个字节,解密得到一个字节再写回去。考虑到解密后的是函数的头部通常是:
55             push ebp
8BEC           mov ebp,esp
用python爆破一下:
for pass1 in xrange(1,10000):
    edx=1
    ecx=pass1+1
    while ecx>1:
        ecx-=1
        edx=(0x00f9*edx) % 0x5ed
        x=edx & 0xff      
    edx=1
    ecx=pass1+1
    while ecx>1:
        ecx-=1
        edx=(0x02c3*edx) % 0x5ed
        y=edx & 0xff
    if x==0x55 and y==0x8b:
print 'pass1: '+str(pass1)
break
跑出来pass1: 4913
重新输入pass1为4913,pass2任意输入:
00401460     53             push ebx
00401461     50             push eax
00401462     56             push esi
00401463     E8 980B0200    call 4.00422000  //在这里断下后进入

    附件 92143
  
   上面是在比较pass2,如果正确则弹出下面的框。
    附件 92144

上传的图像
文件类型: png 1.png (15.2 KB)
文件类型: png 2.png (8.1 KB)
文件类型: png 3.png (6.0 KB)
文件类型: png 4.png (3.4 KB)
文件类型: png 5.png (6.8 KB)
文件类型: png 6.png (65.2 KB)
上传的附件
文件类型: rar 4.rar (89.2 KB)

【招聘】深圳腾讯招聘漏洞安全研究员

$
0
0
职位:Windows漏洞研究员

职位要求:
1. 本科及以上学历,2年以上Windows漏洞分析、利用与挖掘经验;
2. 有较好的逆向功底,熟练使用IDA、Windbg、OD等调试分析工具
3. 熟悉Metasploit等漏洞利用工具,
4. 至少掌握一门编程语言,包括C/C++/Python/Ruby
5. 能够顺畅的阅读漏洞方面的英文资料,具备较强的漏洞学习与理解能力
6. 擅长Windows IE漏洞分析与利用者优先
7. 有Windows漏洞防御开发经验者优先

职位:Android安全研究员

职位要求:

1. 熟悉IDA、Gdb等调试分析工具
2. 熟悉Android开发环境,能够较为熟练的开发Android程序
3. 了解ARM、Smali汇编语言
4. 熟悉Android系统底层原理优先
5. 有Android漏洞挖掘、漏洞利用经验优先

职位:Web安全研究员

职位要求:

1. 熟悉常见的Web安全漏洞及其漏洞利用
2. 熟悉SQL注入、XSS等Web利用知识
3. 至少掌握一门编程语言C/C++/Perl/Python等
4. 有web漏洞挖掘经验者优先

联系方式:

tobywu@tencent.com

调试逆向 【分享】ECC替换公钥实践(上篇)

$
0
0
下篇:http://bbs.pediy.com/showthread.php?t=192245

这段时间花了点时间研究了下怎么替换ECC公钥(v9.2 ~ v11.11.1.1),在这里与感兴趣的朋友分享下。

==================================
生成用自定义公钥、私钥的keygen
==================================
要生成120位SIGN2的ECC license,只要在lm_code.h里加上
#define LM_SIGN_LEVEL LM_SIGN2
#define LM_STRENGTH LM_STRENGTH_239BIT
然后选定一组LM_SEED1,2,3(可以由lmrand1 -seed产生,这里我用的下面这组数),然后编译SDK就可以了。
#define LM_SEED1 0x11111111
#define LM_SEED2 0x22222222
#define LM_SEED3 0x33333333

作为参考,产生的lmcrypt.exe, testlmd.exe见附件,这里选用的是9.2版的SDK,因为有源码,讲解和调试起来都比较方便。

========================================
lmnewgen可以产生lmpubkey.h和lmprikey.h
========================================
请注意下lmprikey.h里的内容,后面会用到
static unsigned char lm_pubkey[2][3][40] = {{{0x77, 0x9c, 0x40, 0xa, 0x58, 0xe2, 0x7c, 0xef, 0xc3, 0xed, 0x93, 0x71, 0x20, 0xe0, 0x97, 0x36},
  {0x76, 0xa1, 0xdd, 0x41, 0x32, 0x8c, 0x52, 0xb9, 0x2b, 0x9d, 0x5b, 0x68, 0xbf, 0x37, 0xbe, 0xa5, 0x82, 0x3f, 0x76, 0xca, 0x92, 0xd2},
  {0x76, 0x9d, 0xe2, 0xab, 0x3b, 0x42, 0xd7, 0x6b, 0x20, 0xb5, 0x46, 0x39, 0xed, 0xbc, 0xa0, 0xd1, 0xcb, 0xb, 0x5d, 0x65, 0xdc, 0xe5, 0x39, 0x63, 0x44, 0x80, 0xcd, 0x78, 0x27, 0x8c, 0x17}}
,
  {{0x77, 0x9b, 0x2f, 0xbb, 0x1f, 0x8, 0x7c, 0x42, 0x93, 0xb6, 0xcb, 0x1, 0x4c, 0x68, 0x8d, 0xb0},
  {0x76, 0x9f, 0xeb, 0xa9, 0x94, 0x3d, 0x5a, 0xba, 0xc, 0x97, 0x1, 0x4a, 0xc8, 0xc2, 0x9f, 0x43, 0xdc, 0xe4, 0xd1, 0x5, 0xf9, 0x84},
  {0x76, 0x9e, 0x6a, 0x55, 0xc2, 0x34, 0xfd, 0x24, 0xf, 0x95, 0xd1, 0x29, 0xbb, 0xf9, 0x1, 0x85, 0x1, 0x3a, 0x53, 0x17, 0x2a, 0x98, 0xbf, 0xb3, 0x62, 0x76, 0xec, 0x9a, 0x87, 0x69, 0x53}}
};
    
static unsigned int lm_pubsize[2][3] = {{0x10, 0x16, 0x1f}
,
  {0x10, 0x16, 0x1f}
};

==============================================================================
1.我们先从获取public key开始(这里以testlmd为例,对实际应用,方法是一样的)
==============================================================================
打开SDK里src\l_prikey.c可以看到下面这段,那么第二个参数(&m->publicKey)存放的就应该是public key了。  

if ((returnValue = sb_ecdsaVerifyEnd( m->global_data, &m->publicKey,
     &ecc_sig, &verifyContext, &verificationResult)) != SB_SUCCESS) 
  {
    l_pubkey_err(job, 10544, returnValue);
    ret = LM_PUBKEY_ERR;
    goto exit_verify;
  }

OD里找到对应的位置下断,
.text:0041D5A9 loc_41D5A9:                             ; CODE XREF: _l_pubkey_verify+7A6j
.text:0041D5A9                                         ; _l_pubkey_verify+7D6j
.text:0041D5A9                 lea     edx, [ebp+verificationResult]
.text:0041D5AC                 push    edx
.text:0041D5AD                 lea     eax, [ebp+verifyContext]
.text:0041D5B3                 push    eax
.text:0041D5B4                 lea     ecx, [ebp+ecc_sig]
.text:0041D5BA                 push    ecx
.text:0041D5BB                 mov     edx, [ebp+m]
.text:0041D5C1                 add     edx, 44h
.text:0041D5C4                 push    edx        <= check edx, will get the public key
.text:0041D5C5                 mov     eax, [ebp+m]
.text:0041D5CB                 mov     ecx, [eax+4]
.text:0041D5CE                 push    ecx
.text:0041D5CF                 call    _sb_ecdsaVerifyEnd

查看0041D5C4处,edx里对应的就是public key

02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4

附件 92215


==================================
2.看看公钥在文件里是怎么存储的
==================================

函数_sb_ecdsaVerifyEnd是被_l_pubkey_verify调用的,好,我们回到函数l_pubkey_verify的起始点开始追踪[00C93B3C~00C93B5E]处是怎么变成public key的。

run过0041D143后,这块内存区域清零

0041D143  |.  E8 E82A0100   CALL testlmd.l_malloc                    ; \l_malloc

附件 92216


在此处下内存写断点,如下图所示,

附件 92217

一路F9很容易来到0041D273处,再来看下内存中的这段数字:

76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17

附件 92218


回头再看下lmpubkey.h里的内容,有点明白了吧?


static unsigned char lm_pubkey[2][3][40] = {{{0x77, 0x9c, 0x40, 0xa, 0x58, 0xe2, 0x7c, 0xef, 0xc3, 0xed, 0x93, 0x71, 0x20, 0xe0, 0x97, 0x36},
  {0x76, 0xa1, 0xdd, 0x41, 0x32, 0x8c, 0x52, 0xb9, 0x2b, 0x9d, 0x5b, 0x68, 0xbf, 0x37, 0xbe, 0xa5, 0x82, 0x3f, 0x76, 0xca, 0x92, 0xd2},
  {0x76, 0x9d, 0xe2, 0xab, 0x3b, 0x42, 0xd7, 0x6b, 0x20, 0xb5, 0x46, 0x39, 0xed, 0xbc, 0xa0, 0xd1, 0xcb, 0xb, 0x5d, 0x65, 0xdc, 0xe5, 0x39, 0x63, 0x44, 0x80, 0xcd, 0x78, 0x27, 0x8c, 0x17}}
,
  {{0x77, 0x9b, 0x2f, 0xbb, 0x1f, 0x8, 0x7c, 0x42, 0x93, 0xb6, 0xcb, 0x1, 0x4c, 0x68, 0x8d, 0xb0},
  {0x76, 0x9f, 0xeb, 0xa9, 0x94, 0x3d, 0x5a, 0xba, 0xc, 0x97, 0x1, 0x4a, 0xc8, 0xc2, 0x9f, 0x43, 0xdc, 0xe4, 0xd1, 0x5, 0xf9, 0x84},
  {0x76, 0x9e, 0x6a, 0x55, 0xc2, 0x34, 0xfd, 0x24, 0xf, 0x95, 0xd1, 0x29, 0xbb, 0xf9, 0x1, 0x85, 0x1, 0x3a, 0x53, 0x17, 0x2a, 0x98, 0xbf, 0xb3, 0x62, 0x76, 0xec, 0x9a, 0x87, 0x69, 0x53}}
};
    
static unsigned int lm_pubsize[2][3] = {{0x10, 0x16, 0x1f}
,
  {0x10, 0x16, 0x1f}
};

好,让我们从0041D273处往回看看这串数字是怎么转换成最终的public key的。

0041D252  |.  0FBE08        |MOVSX ECX,BYTE PTR DS:[EAX]

这里的ECX里的内容是什么:testlmd (daemon name, 对应ASCII码74 65 73 74 6C 6D 64

)

再往下

0041D261  |.  0FB642 48     |MOVZX EAX,BYTE PTR DS:[EDX+48]

EAX里就是上面lmpubkey.h里的第一位数字"76",

0041D265  |.  2BC1          |SUB EAX,ECX
76h- 74h = 02

附件 92220

继续一路下去,
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17  (lmpubkey.h里的public key)
=>
02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4  (真正的public key)


我们用IDA的F5反汇编可以看到这段转换对应的伪代码

          for ( Gi = 0; Gi < pubkeysize[(_DWORD)offset]; ++Gi )
          {
            if ( !*cp )
              cp = job->vendor;
            if ( Gi % 2 )
            {
              if ( Gi % 3 )
                m[Gi + 72] += *cp++;
              else
                m[Gi + 72] ^= *cp++;
            }
            else
            {
              m[Gi + 72] -= *cp++;
            }
          }
          returnValue = sb_dataSize(ellipticCurve, m + 64);

再直观一点就是:
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 - (第0、2、4......26、28、30位用减法运算,比如第0位76-74=02h)
3 9 15 21 27 ^ (第3、9、15、21、27位用异或运算,例如第3位AB^74=DFh)
1 5 7 11 13 17 19 23 25 29 + (第1、5、7......23、25、29位用加法运算,例如第1位9D+65=02,注意取末两位)

0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  <= 0~30(共31 = (1F)h位
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17  <= pubkey in pubkey.h
74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73  <= testlmd
02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4  <= real pubkey(for SIGN2=)

存储在硬盘上的是lmpubkey.h里的public key,经过上面的转化变成真正的public key,所以只要找到lmpubkey中key的存放规律,替换公钥就水到渠成了,这个后面再讲。

(未完待续)

上传的图像
文件类型: jpg Snap1.jpg (132.2 KB)
文件类型: jpg Snap2.jpg (138.2 KB)
文件类型: jpg Snap3.jpg (138.3 KB)
文件类型: jpg Snap4.jpg (135.9 KB)
文件类型: jpg Snap5.jpg (133.9 KB)
上传的附件
文件类型: rar lmcrypt.rar (291.8 KB)
文件类型: rar testlmd.rar (386.0 KB)
文件类型: rar lmnewgen.rar (304.5 KB)

【招聘】安卓/Windows 逆向(反编译)工程师

$
0
0
职位描述:
对新产品或新技术进行技术研究
对安卓应用、游戏进行逆向分析

岗位要求:
熟悉ARM、ASM汇编, 熟悉C语言, 了解C++或Java
熟悉软件逆向静态分析、动态调试、代码跟踪等技能
熟悉各种调试工具:Smali、Dedexer、Dexdump、Apktool、Dex2jar、IDA、OLLYDBG其中一种或多种
熟悉各种通用加密算法
了解PE,ELF,dex 文件格式
了解Android虚拟机Dalvik运行字节码流程
了解Android底层运行机制
有实际相关工作经验1年以上

薪酬与福利:
为吸引、激励社会优秀人才,公司将为员工提供富有竞争力的薪酬体系和完善的福利机制、绩效考核等。

薪 酬
基本工资、年度绩效考核奖金

福 利
我们为员工提供完善的保障计划,包括国家法定的养老保险、医疗保险、工伤保险、失业保险、生育保险,并根据政府政策为员工购买及缴纳住房公积金;

员工生日当月公司为员工准备精美礼品一份

员工假期
公司提供:年休假(5-10天)、双休日/法定公众假期、婚假、丧假、产假、陪产假、哺乳假等相关假期。

员工活动
包括年度2次旅游、部门活动经费等

【原创】新手分析 Splish.exe

$
0
0
这个CrackMe是安于此生安同学翻译的教程里附带的, 算是课后作业, 虽然原理很简单...但对于我来说...还是花了很多时间, 各位轻敲..
感谢安同学...

程序使用汇编编写,分为HardCode 和 name&Serial 两个部分, 第一部分很简单, HardCode包含在代码里, 此处重点分析第二部分;
输入name和Serial, 对GetWindowsTextA下断, 程序会停止两次,

得到储存的地址分别是:
• Name:403236, 字符串长度保存在403463;
• Serial: 403243, 字符串长度保存在403467;
从两个GetWindowsText函数出来就是重要的代码了:
代码:

0040161B  |.  33C9          XOR ECX,ECX
0040161D  |.  33DB          XOR EBX,EBX
0040161F  |.  33D2          XOR EDX,EDX ; 初始化寄存器
00401621  |.  8D35 36324000 LEA ESI,DWORD PTR DS:[403236]  ;装入name字符串的地址
00401627  |.  8D3D 58324000 LEA EDI,DWORD PTR DS:[403258] ;装入目的地址
0040162D  |.  B9 0A000000  MOV ECX,0A
00401632  |>  0FBE041E      /MOVSX EAX,BYTE PTR DS:[ESI+EBX]  ;读入name的第一个字符
00401636  |.  99            |CDQ ; 扩展EAX为 EDX:EAX
00401637  |.  F7F9          |IDIV ECX ; EAX = EAX/ECX; EDX = EAX%EDX, 即字符除以0x0A, 商储存在EAX,余数储存在EDX
00401639  |.  33D3          |XOR EDX,EBX ;将余数和循环变量(第几个字符)异或
0040163B  |.  83C2 02      |ADD EDX,2 ;将得到的值加2
0040163E  |.  80FA 0A      |CMP DL,0A ;将EDX的低8位(上面运算得到的值其实不会超过255, 可以认为EDX = DL, 没错吧? )和0A比较
00401641  |.  7C 03        |JL SHORT Splish.00401646 ;小于0x0A则跳
00401643  |.  80EA 0A      |SUB DL,0A ; 大于0x0A 则减去0x0A, 保证DL < 0x0A就对了
00401646  |>  88141F        |MOV BYTE PTR DS:[EDI+EBX],DL ;将DL存入目的地址
00401649  |.  43            |INC EBX
0040164A  |.  3B1D 63344000 |CMP EBX,DWORD PTR DS:[403463]          ;  循环次数  = 字符串长度
00401650  |.^ 75 E0        \JNZ SHORT Splish.00401632

上面这个函数就得到了name翻译后的编码, 翻译成C语言如下(这里我输入的name就是字符串name):
    char n[4] = {"name"};
    int a[4] = {0};
    int I;
    for (i = 0; i < 4; i++)
    {
        a[i] = n[i] % 0x0A;
        a[i] ^= I;
        a[i] += 2;
        if (a[i] > 0x0A) a[i] -= 0x0A;
        printf("%x",a[i]);
    }

接下来是翻译Serial的, 比上面简单一点
00401652  |.  33C9          XOR ECX,ECX
00401654  |.  33DB          XOR EBX,EBX
00401656  |.  33D2          XOR EDX,EDX ; 清空寄存器
00401658  |.  8D35 42324000 LEA ESI,DWORD PTR DS:[403242] ; 装入Serial的地址
0040165E  |.  8D3D 4D324000 LEA EDI,DWORD PTR DS:[40324D] ;装入目标地址
00401664  |.  B9 0A000000  MOV ECX,0A
00401669  |>  0FBE041E      /MOVSX EAX,BYTE PTR DS:[ESI+EBX] ;把一个字节复制到EAX
0040166D  |.  99            |CDQ
0040166E  |.  F7F9          |IDIV ECX ;同样除以0A
00401670  |.  88141F        |MOV BYTE PTR DS:[EDI+EBX],DL ;直接存入目标地址
00401673  |.  43            |INC EBX
00401674  |.  3B1D 67344000 |CMP EBX,DWORD PTR DS:[403467] ;循环长度为字符串长度
0040167A  |.^ 75 ED        \JNZ SHORT Splish.00401669
0040167C  |.  EB 2A        JMP SHORT Splish.004016A8


004016A8  |>  8D35 4D324000 LEA ESI,DWORD PTR DS:[40324D] ;装入Sreial转换后的地址
004016AE  |.  8D3D 58324000 LEA EDI,DWORD PTR DS:[403258] ; 装入Name转换后的地址
004016B4  |.  33DB          XOR EBX,EBX
004016B6  |>  3B1D 63344000 /CMP EBX,DWORD PTR DS:[403463] ;name的长度作为循环长度
004016BC  |.  74 0F        |JE SHORT Splish.004016CD ;循环结束则跳(跳到成功提示!)
004016BE  |.  0FBE041F      |MOVSX EAX,BYTE PTR DS:[EDI+EBX]  ;装入name的编码中的一个字节
004016C2  |.  0FBE0C1E      |MOVSX ECX,BYTE PTR DS:[ESI+EBX]  ; 装入serial的编码中的一个字节
004016C6  |.  3BC1          |CMP EAX,ECX ;比较
004016C8  |.  75 18        |JNZ SHORT Splish.004016E2 ;不等则跳, 调往错误提示
004016CA  |.  43            |INC EBX
004016CB  |.^ EB E9        \JMP SHORT Splish.004016B6

004016CD  |>  6A 00        PUSH 0                                  ; /Style = MB_OK|MB_APPLMODAL
004016CF  |.  68 0A304000  PUSH Splish.0040300A                    ; |Title = "Splish, Splash"
004016D4  |.  68 42304000  PUSH Splish.00403042                    ; |Text = "Good job, now keygen it."
004016D9  |.  6A 00        PUSH 0                                  ; |hOwner = NULL
004016DB  |.  E8 68000000  CALL <JMP.&USER32.MessageBoxA>          ; \MessageBoxA
004016E0  |.  EB 13        JMP SHORT Splish.004016F5

从整体来看, 就是看name运算后(取余异或再加2)的编码是否等于Serial运算后(取余)的编码, 可以任意指定一个name, 运算出编码后再对编码逆运算就能得到对应的Serial了.
写出完整代码如下:
代码:

#include <stdio.h>
int main()
{
    char n[4] = {"name"};
    char s[4] = {0};
    int a[4] = {0};
    int i, t;
    for (i = 0; i < 4; i++)
    {
        a[i] = n[i] % 0x0A;
        a[i] ^= i;
        a[i] += 2;
        if (a[i] > 0x0A) a[i] -= 0x0A;
        printf("%x",a[i]);
    }
        putchar('\n');
    for (i = 0; i < 4; i++)
    {
      t = a[i];
      while (t < 48 || t > 122) t += 0x0A; //这里要是运算后得到的编码是正常的ASCII, 做了一点限制
      printf("%c",t);
    }
    putchar('\n');
    return 0;
}

算出name对应的Serial是4056;

包含这个Crackme的教程地址: http://bbs.pediy.com/showthread.php?...32#post1282732
继续努力看教程...


截图纪念.

上传的图像
文件类型: png 未命名图片.png (35.8 KB)

调试逆向 【翻译】使用OllyDbg从零开始Cracking 第四十一章-神马是AntiDump

虚拟机保护 【原创】VT调试BluePill的心得

$
0
0
VT虽然已经流行多年,但是因为参考资料较少,所以研究起来有很多困难

要学习VT,最好的参考资料之一就是NewBluePill源代码,该代码是Invisible Things Lab在2007年公开的,实现了一个基本的VMM,并加入了内存隐藏技术。阅读nbp的代码,并结合Intel开发手册作为参考,可以学习到Intel-Vt的方方面面。

因为最近在学校做一个项目,要用VT实现一些功能,所以我开始研究nbp的代码,期间遇到很多问题,困扰了我很久,经过N次BSOD后终于算是勉强把nbp弄明白了:eek:在这里跟大家分享一下经验。

一.搭建调试环境

我搜索了论坛里有关VT调试的帖子,综合了网上的各种说法,普遍认为调试VT有3种方法:
1.Windbg+bochs虚拟机
好处是可以用我们熟悉的windbg
缺点是需要手工修改一些代码并重新编译bochs,很难自己装系统(因为太慢了),最后系统跑起来也感觉特别脆,容易出错,我试了很久好像也没弄好

2.IDA+GDB+bochs
不清楚,因为我一点也不了解GDB,而且我的IDA版本好像有问题,跟bochs配合也是个蛋疼的事情
(看了评论后发现IDA+GDB+VMWare似乎是最好的解决方案,可以独立于操作系统进行调试,不依赖系统资源)

3.两个物理主机通过COM连线,进行双机调试
我有两台机器,一个台式机(有COM口),一个笔记本(没COM,使用USB转COM插头),然后买了个母对母的COM连接线(因为我两个机器端都是公头),连好后却怎么也通讯不了,也不知道问题在哪,感觉特别无奈。。后来某次跟一个做嵌入式的同学聊了聊,他说可能是因为COM线的RXD引脚和TXD引脚需要交叉接,然后就帮我焊了个小板子,回去一试还真行了
http://naylon.0ginr.com/wp-content/uploads/2014/09/QQ图片20140913201924.jpg

这个方法好处是可以用windbg,而且不会出现虚拟机的奇怪问题,绝对原生。缺点是需要两台物理主机,而且还得买线,对环境要求较高。调试速度也一般,因为串口通讯速率毕竟有限。

以上几个方法都不尽人意,但最后我经FC牛的提醒发现一种最完美的方法

4.VMWare10+Windbg

之前我们宁愿用bochs也不用VMWare,是因为VMWare的早期版本并不支持VT的模拟,但是却没有多少人发现VMWare10已经支持VT了。只需要选上这个选项(btw,VM10是原生中文,用着非常爽~)
http://naylon.0ginr.com/wp-content/uploads/2014/09/indeqqqx.png

后面的步骤大家就都懂了,配置一下VMWare跟Windbg的双机调试,就可以用一台电脑拿着windbg调VT了~缺点简直没有,因为这已经是我能想象的最好情况了。

顺便说一下,nbp0.32公开版本的推荐运行环境是Windows 2003 x64,所以我一开始也是先从2k3着手研究的

本文提出的方法不一定正确,但目前可以在一定程度上解决VT调试的一些问题。至于Windbg、内核调试引擎、VMM这三者之间相互作用的细节仍有待实验探究

二、解决断点问题

本以为上文结束后就可以随便调了,不过实际上又有一个奇怪的问题:一旦开启VMLAUNCH了以后,无法在VMM的代码上下断点,比如bp newbp!VmxVmexitHandler,如果断点被触发的话,虚拟机就失去了响应,Windbg也定在那里不动了。这样的话我们根本没法调关键代码,print调试大法必然是不能接受的。

这个问题也让我百思不得其解,直到现在我也不知道为什么会出现这种现象。但是我发现这跟nbp的内存隐藏有关(后记:有待进一步验证),我把nbp自己的内存管理系统取缔以后,就可以任意下断点了。哪位大牛能解释下这个BUG的细节,还望不吝赐教

nbp的内存管理主要实现在paging.c里,观察nbp分配内存使用的MmAllocatePages函数,可以看出它首先用ExAllocatePoolWithTag申请内存,然后会对页做一些处理,来实现自己的内存管理(这部分我还没细看)。我们首先要把后续操作注释掉(MmAllocateContiguousPages和MmAllocateContiguousPagesSpecifyCache同理)
代码:

PVOID NTAPI MmAllocatePages (
  ULONG uNumberOfPages,
  PPHYSICAL_ADDRESS pFirstPagePA
)
{
  PVOID PageVA, FirstPage;
  PHYSICAL_ADDRESS PagePA;
  NTSTATUS Status;
  ULONG i;

  if (!uNumberOfPages)
    return NULL;

  FirstPage = PageVA = ExAllocatePoolWithTag (NonPagedPool, uNumberOfPages * PAGE_SIZE, ITL_TAG);
  if (!PageVA)
    return NULL;
  RtlZeroMemory (PageVA, uNumberOfPages * PAGE_SIZE);

  if (pFirstPagePA)
    *pFirstPagePA = MmGetPhysicalAddress (PageVA);

  /*

  for (i = 0; i < uNumberOfPages; i++) {

    // map to the same addresses in the host pagetables as they are in guest's
    PagePA = MmGetPhysicalAddress (PageVA);
    Status = MmSavePage (PagePA, PageVA, PageVA, !i ? PAT_POOL : PAT_DONT_FREE, uNumberOfPages, 0);
    if (!NT_SUCCESS (Status)) {
      DbgPrint ("MmAllocatePages(): MmSavePage() failed with status 0x%08X\n", Status);
      return NULL;
    }

    Status = MmCreateMapping (PagePA, PageVA, FALSE);
    if (!NT_SUCCESS (Status)) {
      DbgPrint
        ("MmAllocatePages(): MmCreateMapping() failed to map PA 0x%p with status 0x%08X\n", PagePA.QuadPart, Status);
      return NULL;
    }

    PageVA = (PUCHAR) PageVA + PAGE_SIZE;
  }

  */

  return FirstPage;
}

还要注释掉HvmSetupGdt函数里的一句话
代码:

//MmMapGuestTSS64 ((PTSS64) GuestTssBase, GuestTssLimit);
更改VmxSetupVMCS中设置VMCS.CR3的部分,让GuestOS使用当前系统的页目录指针,而非nbp自己的页目录
代码:

  //VmxWrite (HOST_CR3, g_PageMapBasePhysicalAddress.QuadPart);
  VmxWrite (HOST_CR3, RegGetCr3 ());

最后要把DriverEntry中MmInitManager之类的调用删掉,卸载时也不需要MmShutdownManager。

至此便移除了nbp自己实现的内存管理(似乎这技术才是亮点..以后再好好看看)。

http://naylon.0ginr.com/wp-content/uploads/2014/09/indexwww.png

三、解决卸载问题

nbp在卸载时会死机,因为卸载必须在VMM下进行,而DriverUnload是在non-root模式里,所以要通过Hypercall的方法把任务交给VMM,Hypercall的实现在hypercall.c里,DriverUnload最终会调用到HcMakeHypercall,但是nbp却没有对VMCALL指令作处理,只是把它当做一般的VM指令,直接返回执行失败,所以卸载的Hypercall没有被处理,系统仍在虚拟机中运行,但是随后DriverUnload会释放资源,进而导致出错死机。要让它正常卸载,我们只要处理好Hypercall即可。

首先添加对VMCALL的处理函数,修改VmxRegisterTraps

代码:

  //
  // 为所有VM指令造成的VMExit设置一个无用的处理函数,VMCALL则作为Hypercall处理
  //
  for (i = 0; i < sizeof (TableOfVmxExits) / sizeof (ULONG32); i++) {
    if (TableOfVmxExits[i] == EXIT_REASON_VMCALL) {
      if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_VMCALL, 0,      // length of the instruction, 0 means length need to be get from vmcs later.
                                                        VmxDispatchHypercall, &Trap))) {
        _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchHypercall with status 0x%08hX\n", Status));
        return Status;
      }
    } else {
      if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, TableOfVmxExits[i], 0,      // length of the instruction, 0 means length need to be get from vmcs later.
                                                      VmxDispatchVmxInstrDummy, &Trap))) {
        _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchVmon with status 0x%08hX\n", Status));
        return Status;
      }
    }
    TrRegisterTrap (Cpu, Trap);
  }

然后实现Hypercall的处理函数,只需要简单地交给HcDispatchHypercall即可(其实nbp把工作都做好了,只不过把桥梁移除了,感觉nbp代码里很多问题都是作者故意的)。

代码:

static BOOLEAN NTAPI VmxDispatchHypercall (
  PCPU Cpu,
  PGUEST_REGS GuestRegs,
  PNBP_TRAP Trap,
  BOOLEAN WillBeAlsoHandledByGuestHv
)
{
  ULONG64 inst_len;
  ULONG32 exit_qualification;

  if (!Cpu || !GuestRegs)
    return TRUE;

  _KdPrint (("VmxDispatchVminstructionDummy(): Nested virtualization not supported in this build!\n"));

  inst_len = VmxRead (VM_EXIT_INSTRUCTION_LEN);
  Trap->General.RipDelta = inst_len;

  HcDispatchHypercall(Cpu, GuestRegs);

  return TRUE;
}

然后就可以正常卸载nbp了。


还有几个地方比较麻烦,要改的地方比较多。一个是Svm,这个是nbp在AMD处理器下的实现,相当于AMD版的Vt,这个用的比较少,而且内容跟Vt相似,如果只是研究Vt的话可以移除Svm的代码。另外就是x86的移植问题,我感觉nbp本身肯定是在x86下测试过的,但是发布版里故意加了一些BUG,都是一些小毛病,对照着编译错误细心改一下就行,不用很多添加新代码。

最后给出我修改的nbp代码(改的不是很细致,似乎某些多核情况下会BSOD,有时间我再改进)

ps:打个广告,最近在做图像匹配和机器学习方面的研究,不知有没有这方面的大牛能指教一下:3: qq474516292

上传的附件
文件类型: zip nbp-0.32-plus.zip (312.8 KB)

调试逆向 【分享】ECC替换公钥实践(下篇)

$
0
0
上篇总结:
上篇链接:http://bbs.pediy.com/showthread.php?t=192180

(a) 在lm_code.h中,选定LM_SEED1.2,3, private key、public key也就固定了;

(b) 可以用lmnewgen输出lmprikey.h和lmpubkey.h查看private key和public key,高版本的SDK,缺省只输出lmprikey.h,加上-pubkey选项,可以输出lmpubkey.h;

(c) lmpubkey.h中存放的是转换过的public key,转换规律是用lmpubkey.h中的key和daemon( 比如本例中的testlmd)的ASCII代码按位做加、减或异或操作得到真正的公钥,具体如下:
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 - (第0、2、4......26、28、30位用减法运算,比如第0位76-74=02h)
3 9 15 21 27 ^ (第3、9、15、21、27位用异或运算,例如第3位AB^74=DFh)
1 5 7 11 13 17 19 23 25 29 + (第1、5、7......23、25、29位用加法运算,例如第1位9D+65=02,注意取末两位)
0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  <= 0~30(共31 = (1F)h位
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17  <= pubkey in pubkey.h
74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73  <= testlmd
02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4  <= real pubkey(for SIGN2=)


替换公钥,就是找出lmpubkey.h中的pubkey在硬盘上是如何存储的,找到存储的位置,相应地替换成自己的lmpubkey.h中的public key就可以了。

好,我们开始下篇。

上篇我么在内存[00C93B3C~00C93B5E]处下写断点追踪出

76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17 (lmpubkey.h中的 public key)
=>
02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4 (真实的public key)

现在我么再回头看看这段内存里的public key是怎么来的
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17

和上篇一样,在run过0041D143后,这块内存区域清零
0041D143  |.  E8 E82A0100   CALL testlmd.l_malloc                    ; \l_malloc

在此处下内存写断点,如下图所示,

附件 92208


按一次F9到停在0047F195,

0047F195  |.  F3:AB         REP STOS DWORD PTR ES:[EDI]

F8跳过,再按一次F9来到0047BEF4

0047BEF4   .  89448F E4     MOV DWORD PTR DS:[EDI+ECX*4-1C],EAX

看下信息窗口里的EAX,此处就是开始往[00C93B3C~00C93B5E]里写“76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17”了

EAX=ABE29D76
DS:[00C93B40]=00000000
MEMCPY.ASM:283. 

附件 92209

往上一步,看看EAX的值是怎么来的

0047BEF0   > \8B448E E4     MOV EAX,DWORD PTR DS:[ESI+ECX*4-1C]

EAX由[ESI+ECX*4-1C] = [00a66744]赋值而来

附件 92210


好了,再往回trace,看看内存[00a66744-00a66762]的赋值是怎么来的,可以看到在_l_public_key_verify的入口处,这段内存的值已经存在了,那就再看看_l_public_key_verify的调用函数的入口处。

* 这里注意下,IDA里看不到哪里调用了_l_public_key_verify,可以在OD里运行到_l_public_key_verify的入口处0041CDB0,然后按“调试”->“执行到返回”(或者按快捷键CTRL+F9),找到_l_public_key_verify调用函数。

这么一路追踪下去(得有耐心,比较耗时间,但没什么难度,如果看到这段值从某处内存拷贝过来,就再去看看那段内存值是怎么来的),最终会找到这里

004A286A  |.  FF15 F47E5200 CALL DWORD PTR DS:[l_n36_buf]            ; \testlmd.00401E60

run过004A286A后,内存[0012F184 - 0012F1A2]里的值为
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17

附件 92211


我么再往回,在004A286A处按F7进去看看

run过0040326B清零

0040326B  |.  E8 E0BE0700   CALL testlmd.memset                      ; \memset


还是老办法,在内存[0012F184 - 0012F1A2]下写断点,

附件 92212


然后一路F9,你会看到下面的数字一个个的出现(但是不是按顺序的,第一个出现的是在.text:403C0A,往内存0012F196处写5D,最后一个出现的是.text:00412AAE,往内存0012F190处写ED)。
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17

好,看看第一个出现的5D怎么来的。
00403C0A  |.  0305 30775200 ADD EAX,DWORD PTR DS:[527730]
00403C10  |.  8B4D 0C       MOV ECX,DWORD PTR SS:[EBP+C]
00403C13  |.  8881 AA000000 MOV BYTE PTR DS:[ECX+AA],AL

附件 92213


呵呵,接近成功了,看到这个固定的数了吧,[527730],里面放的是5D,回到程序还没开始运行时,看看,这个值是不是已经在那了,说明什么,这个值是直接存在硬盘上的值了。其余的也可以这么一个一个找到。

呵呵,终于找到pubkey存放的源头了,替换公钥就是把这些值一个一个的替换成自己定义的pubkey就行了。

休息一下,往下再讲除了手工替换,怎么用程序来自动替换。

上传的图像
文件类型: jpg Snap8_1.jpg (135.7 KB)
文件类型: jpg Snap8_2.jpg (140.7 KB)
文件类型: jpg Snap10.jpg (139.4 KB)
文件类型: jpg Snap11.jpg (128.9 KB)
文件类型: jpg Snap12.jpg (129.3 KB)
文件类型: jpg Snap_write_lmpubkey_1.jpg (128.9 KB)

【原创】飘云qq显ip去广告源代码

$
0
0
这是我几年前做的飘云qq的源代码,只适用于qq2008以下版本

上传的附件
文件类型: rar IPPlugin.rar (572.1 KB)

【原创】定制属于自己的so壳

$
0
0
http://lab.nagapt.com/ 这个网址,是我们自己发布一些好玩技术的网站,以后有好玩的东西,或者比较cool的东西,都会往上放。

现在上面有一套sdk,如果谁有兴趣,写so保护壳,可以参照sdk里面的例子。进行编写, 我们做了一个链接器,可以将两个so链接到一起。 把壳so当作开发库,直接链接到目标文件上,并对目标文件进行加密操作。

因为人力以及时间原因,我们不能立刻把这套系统搬上线。目前只能以这样的形式来搞。 以后会慢慢做到线上,提供给论友玩耍。

如果你觉得还不错,可以把编译好后的so文件给我发邮件 yanwenbin@nagapt.com。我会帮你们加测试程序,然后发给你们。 但是由于这事情是我一个人来搞,所以可能效率上不一定及时回复。 见谅。。。

【原创】盘古越狱工具在用户空间的行为

$
0
0
背景知识
盘古在用户空间主要利用了iOS安装程序的一个漏洞,这里先列出安装一个应用的主要过程:
附件 92287
整个安装过程分为12个阶段,上图只是列出了起点、终点还是对盘古越狱来说比较重要的阶段。大家注意上图红线所示的时间区间,在这个区间内如果在“Staging Directory”中创建一个符号链接指向沙盒之外,就可以利用解压程序向系统目录写入文件。同时也可以通过控制压缩包中的文件列表,在起始处放一个大文件,从而在解压过程中创建一个符号链接。这是在盘古在安装过程中利用的主要漏洞,后面介绍的盘古在用户空间的行为基本都是围绕这个漏洞。
主要的组件
盘古主要由四部分组成,:
1、桌面程序:提供资源,控制越狱流程。
2、com.pangu.ipa1.ipa:Socket Server,与桌面程序配合制造竞态条件。
3、pangu.dylib,Socket Server,利用内核漏洞安装Untecher,Cydia等。
4、pangu.tar,Untecher
这里主要涉及的是前两个组件,及第三个组件中用户空间相关的部分。
工作流程
说明:为了验证自己的分析是正确的,用Python重新实现了盘古桌面程序的功能,利用盘古的Payload可以实现越狱,下面会在主要阶段给出相应示例代码。
阶段一:安装辅助程序,获取相关资源
1、安装com.pangu.ipa1.ipa
代码:

def install_pangu():
    lockdown = LockdownClient()
    afc = AFCClient(lockdown)
    mci = lockdown.startService("com.apple.mobile.installation_proxy")
 
    file_name = "com.pangu.ipa1.ipa"
    afc.set_file_contents("/PublicStaging/" + file_name, open("payload/" + file_name,"rb").read())
    mci.sendPlist({"Command":"Install", "PackagePath": "/PublicStaging/" + file_name})
    while True:
        status =  mci.recvPlist()
        if not status:
            break
        completion = status.get("PercentComplete")
        if completion:
            print "Installing, %s: %s %% Complete" % ("com.pangu.ipa1.ipa", status["PercentComplete"])
        if status.get("Status") == "Complete":
            print "Installation %s\n" % status["Status"]
            break
    mci.close()
    afc.stop_session()
    lockdown.stop_session()

首先利用AFC服务将IPA传到设备上,然后利用 Installation Proxy 安装应用。
2、获取Cache
代码:

def download_caches():
    fc = FileRelayClient()
    data = fc.request_sources(["Caches"])
    fc.stop_session()
    if data:
        file_path = "./payload/caches.gz"
        output_path = "./payload/caches"
        open(file_path,"wb").write(data)
        print  "Data saved to:  %s " % file_path
        with open(file_path, "r") as f:
            gz = gzip.GzipFile(mode="rb", fileobj=f)
            cpio = CpioArchive(fileobj=BytesIO(gz.read()))
            cpio.extract_files(files=None,outpath=output_path)
    else:
        print "Fail to get caches"
        raise Exception("Fail to get caches")

调用 FileRelay 服务,获取Cache,主要是从中拿到com.apple.mobile.installation.plist
3、修改 com.apple.mobile.installation.plist
修改是针对盘古程序的,具体修改如下:
代码:

CFBundleExecutable = "../../../../../../usr/libexec/lockdownd";
EnvironmentVariables = { DYLD_INSERT_LIBRARIES = "/private/var/mobile/Media/Pangu-Install/pangu.dylib"; };

4、修改盘古程序的Info.plist
代码:

CFBundleExecutable = "../../../../../../usr/libexec/lockdownd";
5、构造applicationState.plist
代码:

{ "com.pangu.ipa1" = { SBApplicationAutoLaunchForVoIP = :true; }; }
这个会造成盘古程序在设备重启后自动运行。
6、com.apple.LaunchServices-056.csstore 主要是为了更新程序列表
7、com.apple.backboardd.plist 禁用“看门狗”
基于上述文件盘古会构造三个Payload。
代码:

def generate_upgrade_bundle1():
    guid_str = get_guid()
    with ZipFile("./payload/upgrade1.zip", "w") as payload:
        payload.write("./payload/upgrade_bundle/bigfile", "/tmp/bigfile")
        payload.write("./payload/upgrade_bundle/com.apple.LaunchServices-056.csstore", "/mobile/Library/Caches/com.apple.LaunchServices-056.csstore")
        payload.write("./payload/upgrade_bundle/com.apple.mobile.installation.plist", "/mobile/Library/Caches/com.apple.mobile.installation.plist")
        payload.write("./payload/upgrade_bundle/applicationState.plist", "/mobile/Library/BackBoard/applicationState.plist")
        payload.write("./payload/upgrade_bundle/com.apple.backboardd.plist", "/mobile/Library/Preferences/com.apple.backboardd.plist")
        payload.write("./payload/upgrade_bundle/Info.plist", "/mobile/Applications/" + guid_str + "/ipa1.app/Info.plist")
 
def generate_upgrade_bundle2():
    # os.remove("./payload/upgrade2.zip")
    guid_str = get_guid()
    with ZipFile("./payload/upgrade2.zip", "w") as payload:
        payload.write("./payload/upgrade_bundle/bigfile", "/tmp/bigfile")
        payload.write("./payload/upgrade_bundle/com.apple.mobile.installation.plist", "/mobile/Library/Caches/com.apple.mobile.installation.plist")

def generate_upgrade_bundle3():
    # os.remove("./payload/upgrade3.zip")
    guid_str = get_guid()
    with ZipFile("./payload/upgrade3.zip", "w") as payload:
        payload.write("./payload/upgrade_bundle/bigfile", "/tmp/bigfile")
payload.write("./payload/upgrade_bundle/com.apple.LaunchServices-056.csstore", "/mobile/Library/Caches/com.apple.LaunchServices-056.csstore")

这个阶段会知道三个程序升级包,供下一阶段使用。
另外,可以简单的理解为:执行完这个阶段就对应着盘古提示用户在手机上启动程序。

阶段二:利用竞态条件安装文件,构造环境执行pangu.dylib
当用户在手机上启动程序后,手机上的App会启动一个Socket Server,等待桌面程序的握手,这个握手的暗语挺有意思。桌面向App发送:PING,App收到后回应桌面:PONG。在握手完成后,盘古开始利用静态条件将如上构造的三个Payload安装到手机上。
具体过程为首先利用安装服务安装升级包,在安装的过程中桌面向App发送starthook,具体hook的内容可以通过调试App确定是创建一个符号链接:

代码:

"/private/var/tmp/install_staging.eP7ZzJ/foo_extracted" ---> "/var/"
其中后缀部分会因为每次安装而不同。
示例代码:

代码:

def fire_race_condition(lockdown, file_name):
    mci = lockdown.startService("com.apple.mobile.installation_proxy")
    sock = get_sock()
    print "----->PING"
    sock.send("PING")
    msg = sock.recv(4)
    if msg == "PONG":
        print "<-----PONG\n"
    upgrade_pangu(mci, file_name)
    print "----->starthook"
    sock.send("starthook")
    msg = sock.recv(4)
    if msg == "succ":
        print "<-----success\n"
    else:
        print "<-----fail\n"

在完成安装三个Payload之后,盘古会上传文件到Media中的 Pangu-Install目录:
Cydia.tar
packagelist.tar
pangu.dylib
pangu.tar
pangu_ex.tar

至此,盘古基本完成了用户空间的行为,在界面上的反应为:盘古会第一次重启设备。
阶段三:利用漏洞安装Untecher,Cydia
设备重启完成后,pangu.dylib会被加载,并启动一个 Socket Server。桌面程序在检测到设备加载后会向 pangu.dylib 发送:55AA,pangu.dylib 接到 55AA后开始安装Untecher、Cydia。
阶段四:清理
在pangu.dylib完成工作后,向桌面程序发送:AA55,桌面程序开始清理临时文件,删除Provisional文件,恢复设备时间等操作。在完成清理操作后,桌面程序会第二次重启设备,至此越狱完成。

上传的图像
文件类型: png Installflow.png (37.4 KB)

调试逆向 【原创】手工打造PE文件 附上可执行源码 win7 vs2010工程

$
0
0
经过了几天折腾,参考了各种各样的资料,把看雪大婶们的《加密与解密 第三版》讲PE的部分都翻烂了,:eek::eek:折腾出这一段代码,执行程序,会生成一个PE文件,执行生成的PE文件,弹出经典的hello :cool:





先发一个工程,等周末有时间了再写一篇文章来详细解读代码...

上传的附件
文件类型: rar ManualPE 9-18.rar (38.3 KB)

【招聘】北京耘升天下诚聘 Android(Root)高级工程师(专兼职均可)

$
0
0
目前公司正处于飞速发展阶段,我们追求“速度与激情”,我们关注“创新与学习”。

欢迎跟我们有共同志向的互联网人加入我们的团队,您的创意和理想将在这里实现!

公司除了提供具有竞争力的薪酬外,还将提供:
1. 轻松和谐的办公环境;
2. 每天七小时,每周五天工作制,不提倡加班,讲究效率;
3. 五险一金等国家基础福利待遇;
4. 免费早餐、水果及下午茶福利;
5. 公司配备台球、桌上足球、XBOX等供大家休闲娱乐;
6. 有效的Root新方案的专门奖励;
7. 节日、生日、新婚、生子....总经理亲自封发红包;
8. 及时转正、调薪、奖励...的人才激励态度;
9. 带薪年假;
10. 定期组织旅游、聚餐等活动;
11. 每周组织轻松的业内资讯分享会,愿意平等的倾听大家的想法和见解,给予开放的、广阔的发展空间;
.
.
.
我不想说快到碗里来...
碗,太小!
装不下你的未来!
我想说:
这里的世界是你可以主宰的!


对于优秀的候选人,也可以选择兼职,不限制工作地点、方式和时间。

虚拟机保护 【原创】用Oreans UnVirtualizer还原VM代码

$
0
0
标题:【原创】用Oreans UnVirtualizer还原VM代码实验
作者:sungy
时间:2014-09-18

对VM一直很头痛,在逆向实践一般尽量想办法避开它,当黑盒来处理。有时候不面对她又不行,正好在论坛上看了Oreans UnVirtualizer插件,拿来实践学习下。新手可以了解下恢复VM代码的过程,高手可以帮助纠正错误并指导深入

相关工具可在看雪及网上找到:
Oreans UnVirtualizer VM恢复插件
Code Virtualizer v1.3.8 加密工具
OD 调试工具

加密目标程序源码选择Code Virtualizer v1.3.8中自带的例子
路径:\Examples\C\VC\32-bit\Via API
编译环境 VC6.0

先观察下源码中准备加密的部分
代码:

//////////////////////////////////////////////////////////////////////////////////////////////////////
if (LOWORD(wParam) == IDC_BUTTON_ENCODE1)
        {
 
            // the following code, inside the VIRTUALIZER macro, will be converted
                        // into virtual opcodes
     
            VIRTUALIZER_START  //VM开始标志宏

            for (int i = 0; i < 10; i++)
            {
                value += value * i;
            }

            MessageBox(NULL, "This is the Virtualizer macro #1", "Virtualizer Macro", MB_OK + MB_ICONINFORMATION);

            VIRTUALIZER_END  //VM结束标志宏

                }
        else if (LOWORD(wParam) == IDC_BUTTON_ENCODE2)
        {
 
            // the following code, inside the VIRTUALIZER macro, will be converted
                        // into virtual opcodes
     
            VIRTUALIZER_MUTATE2_START  //VM开始2

            for (int i = 0; i < 10; i++)
            {
                value += value * i * 3;
            }

            MessageBox(NULL, "This is the Virtualizer with mutation level 2", "Virtualizer Macro", MB_OK + MB_ICONINFORMATION);

            VIRTUALIZER_END //VM结束2

                }

///////////////////////////////////////////////////////////////////////////////////////////////////////

用Code Virtualizer 载入编译链接后生成的目标程序:vc_example.exe
附件 92305

保护选项就默认吧:
附件 92306

代码虚拟选项:
附件 92308
点击相应的加密块,下面的汇编代码窗口出现对应的汇编代码,这个也可以在OD中得到验证
附件 92309

点Protect按钮实施保护,生成VM过的程序,我们叫vmtest.exe吧
附件 92310

现在用OD载入VM过的程序vmtest.exe,Ctrl+G 来到0040111C ,看到了吗,被VM蹂躏的实景如此! 到00401167时结束,又变成能看懂的汇编代码了
附件 92311

同理可以观察另一代VM过的代码:0040117F - 004011CD

好,现在来看看怎么用Oreans UnVirtualizer 1.8插件(OreansUnVirtualizer.dll)来恢复吧

解压插件后放到od-plug目录,用OD载入vmtest.exe,Ctrl+G 来到0040111C,此行右击鼠标选择Oreans UnVirtualizer - Find References,
附件 92312
填写vm开始地址和大小,大小可以放大些,如果不清楚的话。
附件 92313
出现下面的窗口,最小化它
附件 92314

在0040111C右键选择下面
附件 92315
确定后出现一个记事本,里面是已经还原了的VM汇编代码
附件 92316

对照VM加密前的汇编代码发现基本一致。

到此终于对VM代码还原有一个初步的接触,这个插件我也是刚玩,细节的东西还不了解,请高手回复指导,指正错误,推荐其它好用的VM修复插件及使用方法,谢谢。交流南鹅:659076544

上传的图像
文件类型: png codevirtual.png (85.8 KB)
文件类型: png cv2.png (95.1 KB)
文件类型: png cv3.png (86.0 KB)
文件类型: png cv4.png (88.5 KB)
文件类型: png vm1.png (22.8 KB)
文件类型: png protect.png (17.3 KB)
文件类型: png odvm.png (7.6 KB)
文件类型: png oufind.png (6.6 KB)
文件类型: png 20140919005807.png (4.5 KB)
文件类型: png vmod2.png (4.5 KB)
文件类型: png odvm3.png (3.2 KB)
文件类型: png jmla6.png (31.9 KB)

【原创】【原创】crc32crackme程序分析

$
0
0
crc32crackme.exe这个程序下到电脑有一段时间了,一直没有时间分析。晚上有时间就简单分析了一下。大牛略过:p:。图片传送失败,直接上代码吧。
程序无壳,直接拖入OD分析。
在模块之间调用对GetWindowTextA、MessageBoxA下断,F9让程序跑起来。在弹出的对话框中输入。
Name:obabydbg
Code:123456789
点击CheckMe。
断在这里。
004042F4  |.  50            PUSH EAX                                 ; |Buffer
004042F5  |.  A1 28654000   MOV EAX,DWORD PTR DS:[406528]            ; |
004042FA  |.  50            PUSH EAX                                 ; |hWnd => 00030272 (class='Edit',parent=0033004C)
004042FB  |.  E8 DCF9FFFF   CALL <JMP.&user32.GetWindowTextA>        ; \GetWindowTextA
00404300  |.  83FE 05       CMP ESI,5                                ;  输入用户名大于5
00404303  |.  0F8C B1000000 JL crc32cra.004043BA
00404309  |.  8D45 FC       LEA EAX,DWORD PTR SS:[EBP-4]
0040430C  |.  8B4D FC       MOV ECX,DWORD PTR SS:[EBP-4]
0040430F  |.  BA F8434000   MOV EDX,crc32cra.004043F8                ;  ASCII "DiKeN"
00404314  |.  E8 03ECFFFF   CALL crc32cra.00402F1C                   ;  DiKeN和obabydbg连接
00404319  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
0040431C  |.  E8 AFEBFFFF   CALL crc32cra.00402ED0
00404321  |.  8BD0          MOV EDX,EAX
00404323  |.  8D45 FC       LEA EAX,DWORD PTR SS:[EBP-4]
00404326  |.  E8 C5FAFFFF   CALL crc32cra.00403DF0                   ;  用户名算法

输入的Name要大于5,然后会跟字符串DiKeN连接成DiKeNobabydbg。进入00404326这个CALL中。
00403DF0   $  51            PUSH ECX
00403DF1   .  53            PUSH EBX
00403DF2   .  56            PUSH ESI
00403DF3   .  57            PUSH EDI
00403DF4   .  BF 1A3E4000   MOV EDI,crc32cra.00403E1A
00403DF9   .  8B30          MOV ESI,DWORD PTR DS:[EAX]
00403DFB   .  83C8 FF       OR EAX,FFFFFFFF
00403DFE   .  31C9          XOR ECX,ECX
00403E00   >  3206          XOR AL,BYTE PTR DS:[ESI]                 ;  把用户名做运算,生成一个32位的数值
00403E02   .  50            PUSH EAX
00403E03   .  25 FF000000   AND EAX,0FF
00403E08   .  8B1C87        MOV EBX,DWORD PTR DS:[EDI+EAX*4]
00403E0B   .  58            POP EAX
00403E0C   .  C1E8 08       SHR EAX,8
00403E0F   .  31D8          XOR EAX,EBX
00403E11   .  46            INC ESI
00403E12   .  4A            DEC EDX
00403E13   .^ 75 EB         JNZ SHORT crc32cra.00403E00


这里实际上是把用户名做运算,得到一个32位的数值。DiKeNobabydbg我这里得出来的数值为:0xfb000411。其实也模仿上面的代码写程序得出这个值。
F8继续运行程序,断在这里。
00404356  |> \6A 20         PUSH 20
00404358  |.  8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]
0040435B  |.  E8 40ECFFFF   CALL crc32cra.00402FA0
00404360  |.  50            PUSH EAX                                 ; |Buffer
00404361  |.  A1 2C654000   MOV EAX,DWORD PTR DS:[40652C]            ; |
00404366  |.  50            PUSH EAX                                 ; |hWnd => 00030270 (class='Edit',parent=0033004C)
00404367  |.  E8 70F9FFFF   CALL <JMP.&user32.GetWindowTextA>        ; \GetWindowTextA
0040436C  |.  8D45 F8       LEA EAX,DWORD PTR SS:[EBP-8]
0040436F  |.  8B4D F8       MOV ECX,DWORD PTR SS:[EBP-8]
00404372  |.  BA 08444000   MOV EDX,crc32cra.00404408
00404377  |.  E8 A0EBFFFF   CALL crc32cra.00402F1C
0040437C  |.  8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]
0040437F  |.  E8 A0FEFFFF   CALL crc32cra.00404224                   ;  注册码的算法
00404384  |.  33F0          XOR ESI,EAX                              ;  用户名生成的数值跟注册码生成的数值异域
进行0040437F这个CALL中。
00404261  |.  B8 01000000   MOV EAX,1
00404266  |>  03D2          /ADD EDX,EDX                             ;  主要是在这里生成的
00404268  |.  8D1492        |LEA EDX,DWORD PTR DS:[EDX+EDX*4]
0040426B  |.  8B5D F8       |MOV EBX,DWORD PTR SS:[EBP-8]
0040426E  |.  0FB65C03 FF   |MOVZX EBX,BYTE PTR DS:[EBX+EAX-1]
00404273  |.  03D3          |ADD EDX,EBX
00404275  |.  83EA 30       |SUB EDX,30
00404278  |.  40            |INC EAX
00404279  |.  3BC8          |CMP ECX,EAX
0040427B  |.^ 75 E9         \JNZ SHORT crc32cra.00404266
这里是主要算法。
然后把Name运算得出的数值跟Code字符串通过算法得出来的值做异或,如果为0就正确。
0xfb000411这个值是通过Name得出来的,如果异或要为0的话,那么通过Code得出的值也必须是0xfb000411。这样的话异或运算才得为0。
通过对代码的分析,把0123456789这个字符串运算成要异或的值。既然有正确的值了,那么就通过0xfb000411这个值把字符串逆算出来。
以下为逆算的代码,代码还可以优化,有兴趣的朋友可以修改。
#include <stdio.h>
#include <stdlib.h>


int main()
{
  unsigned int crc32=0xfb000411;
  unsigned int buffer[20];
  char value[20];
  int i=0;
  int j=0;
  int temp=0;
  while(1)
  {
    if(crc32>=0 && crc32<=0x4a)
      break;
    crc32/=5;
    crc32/=2;
    buffer[i] = crc32;
    i++;
  }
  i-=2;
  temp = crc32;
  temp+=0x30;
  value[j]=(char )temp;
  j+=1;
  while(i>=0)
  {
    crc32*=2;
    crc32*=5;
    temp = buffer[i];
    temp-=crc32;
    temp+=0x30;
    value[j]=temp;
    crc32 = buffer[i];
    i--;
    j++;
  }
  crc32*=2;
  crc32*=5;
  temp = 0xfb000411 - crc32;
  temp+=0x30;
  value[j] = temp;
  value[j+1]='\0';
  printf("%s\n",value);
  return 0;
}
我这里得出来的字符串为:Z11082257
注册正确:D:
文字编辑看起来有点乱,大家就将就着看看吧。:eek:

【原创】浅谈一下FS段寄存器在用户层和内核层的使用

$
0
0
菜鸟一枚,有一段时间不搞内核了,分享一下以前学习的结果,有不对的地方请各位指点,大牛飘过~~
在R0和R3时,FS段寄存器分别指向GDT中的不同段:在R3下,FS段寄存器的值是0x3B,在R0下,FS段寄存器的值是0x30。分别用OD和Windbg在R3和R0下查看寄存器(XP3),下图:
附件 92394
附件 92395

FS寄存器的改变是从R3进入R0后和从R0退回到R3前完成的,也就是说:都是在R0下给FS赋不同值的。(FS在R0和R3中是不同的值,在 KiFastCallEntry / KiSystemService中FS值由0x3B变成0x30在 KiSystemCallExit / KiSystemCallExitBranch / KiSystemCallExit2 中再将R3的FS恢复)

一.R3与R0之间的互相转换
代码:

6
nt!KiSystemService:
808696a1 6a00            push    0
808696a3 55              push    ebp
808696a4 53              push    ebx
808696a5 56              push    esi
808696a6 57              push    edi
808696a7 0fa0            push    fs    //旧的R3 下的FS 保存入栈 
808696a9 bb30000000      mov     ebx,30h
808696ae 668ee3          mov     fs,bx   //FS=0X30  FS 值变成了0X30. 
808696b1 64ff3500000000  push    dword ptr fs:[0]
808696b8 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh
808696c3 648b3524010000  mov     esi,dword ptr fs:[124h]  //ESI=_ETHEAD
808696ca ffb640010000    push    dword ptr [esi+140h]     //PreviousMode
808696d0 83ec48          sub     esp,48h                  
808696d3 8b5c246c        mov     ebx,dword ptr [esp+6Ch]  

KiSystemCallExit部分代码
代码:

80869945 8d6550          lea     esp,[ebp+50h]
80869948 0fa1            pop     fs // 恢复 FS 值 
8086994a 8d6554          lea     esp,[ebp+54h]
8086994d 5f              pop     edi
8086994e 5e              pop     esi
8086994f 5b              pop     ebx
80869950 5d              pop     ebp
80869951 66817c24088000  cmp     word ptr [esp+8],80h

二.R3下的FS
当线程运行在R3下时,FS指向的段是GDT中的0x3B段。该段的长度为4K,基地址为当前线程的线程环境块(TEB),所以该段也被称为“TEB段”。因为Windows中线程是不停切换的,所以该段的基地址值将随线程切换而改变的。Windows2000中进程环境块(PEB)的地址为0X7FFDF000,该进程的第一个线程的TEB地址为0X7FFDE000,第二个TEB的地址为0X7FFDD000…。。但是在WindowsXP SP3 下这些结构的地址都是随机映射的。所以进程的PEB的地址只能通过FS:[0x30]来获取了。Windows中每个线程都有一个ETHREAD结构,该结构的TEB成员(其实是KTHREAD中的成员,而KTHREAD又是ETHREAD的成员)是用来保存线程的TEB地址的,当线程切换时,Windows就会用该值来更改GDT的0x30段描述符的基地址值。
代码:

nt!_TEB
   +0x000 NtTib            : _NT_TIB
      +0x000 ExceptionList    : Ptr32
      +0x004 StackBase        : Ptr32
      +0x008 StackLimit       : Ptr32
      +0x00c SubSystemTib     : Ptr32
      +0x010 FiberData        : Ptr32
      +0x010 Version          : Uint4B
      +0x014 ArbitraryUserPointer : Ptr32
      +0x018 Self             : Ptr32    //TEB
   +0x01c EnvironmentPointer : Ptr32
   +0x020 ClientId         : _CLIENT_ID
      +0x000 UniqueProcess    : Ptr32
      +0x004 UniqueThread     : Ptr32
   +0x028 ActiveRpcHandle  : Ptr32
   +0x02c ThreadLocalStoragePointer : Ptr32
   +0x030 ProcessEnvironmentBlock : Ptr32   //PEB
   +0x034 LastErrorValue   : Uint4B
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread  : Ptr32
   +0x040 Win32ThreadInfo  : Ptr32

FS:[0X18] 就是TEB 所在的地址;FS:[0X30] 就是PEB 所在的地址

三.在R0下的FS
代码:

kd> dg 8 0x40
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0008 00000000 ffffffff Code RE    0 Bg Pg P  Nl 00000c9a
0010 00000000 ffffffff Data RW    0 Bg Pg P  Nl 00000c92
0018 00000000 ffffffff Code RE    3 Bg Pg P  Nl 00000cfa
0020 00000000 ffffffff Data RW    3 Bg Pg P  Nl 00000cf2
0028 80042000 000020ab TSS32 Busy 0 Nb By P  Nl 0000008b
0030 ffdff000 00001fff Data RW    0 Bg Pg P  Nl 00000c92
0038 00000000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3
0040 00000400 0000ffff Data RW    3 Nb By P  Nl 000000f2

当线程运行在R0下时, FS指向的段是GDT中的0x30段。该段的长度也为4K,基地址为0xFFDFF000。该地址指向系统的处理器控制区域(KPCR)。这个区域中保存这处理器相关的一些重要数据值,如GDT、IDT表的值等等。

代码:

kd> dt nt!_kpcr
nt!_KPCR
        +0x000 NtTib                 : _NT_TIB
        +0x01c SelfPcr               : Ptr32 _KPCR    //KPCR
        +0x020 Prcb                  : Ptr32 _KPRCB
        +0x024 Irql                  : UChar
        +0x028 IRR                   : Uint4B
        +0x02c IrrActive             : Uint4B
        +0x030 IDR                   : Uint4B
        +0x034 KdVersionBlock        : Ptr32 Void
        +0x038 IDT                   : Ptr32 _KIDTENTRY
        +0x03c GDT                   : Ptr32 _KGDTENTRY
        +0x040 TSS                   : Ptr32 _KTSS
        +0x044 MajorVersion          : Uint2B
        +0x046 MinorVersion          : Uint2B
        +0x048 SetMember             : Uint4B
        +0x04c StallScaleFactor : Uint4B
        +0x050 DebugActive           : UChar
        +0x051 Number                : UChar
        +0x052 Spare0                : UChar
        +0x053 SecondLevelCacheAssociativity : UChar
        +0x054 VdmAlert              : Uint4B
        +0x058 KernelReserved        : [14] Uint4B
        +0x090 SecondLevelCacheSize : Uint4B
        +0x094 HalReserved           : [16] Uint4B
        +0x0d4 InterruptMode         : Uint4B
        +0x0d8 Spare1                : UChar
        +0x0dc KernelReserved2       : [17] Uint4B
   +0x120 PrcbData              : _KPRCB

展开_NT_TIB
代码:

kd> dt _NT_TIB
nt!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   +0x00c SubSystemTib     : Ptr32 Void
   +0x010 FiberData        : Ptr32 Void
   +0x010 Version          : Uint4B
   +0x014 ArbitraryUserPointer : Ptr32 Void
   +0x018 Self             : Ptr32 _NT_TIB    //TEB

看两个地址0x18和0x1C 。在TEB中0x18指向自己,即 TEB 。而 KPCR 中指向自己的确是 0x1C ;0x18 却是指向当前线程的 TEB ,所以 0x18 字段名叫做Self-used 比较确切( WIN2K 源码如此定义)。总之,不管是在R3还是R0 ,FS:[0x18] 总是指向当前线程的 TEB 。

实例1:
获取KTHREAD
展开KPCR后,再次展开kpcrb
代码:

kd> dt nt!_kprcb
nt!_KPRCB
        +0x000 MinorVersion          : Uint2B
        +0x002 MajorVersion          : Uint2B
        +0x004 CurrentThread         : Ptr32 _KTHREAD
        +0x008 NextThread            : Ptr32 _KTHREAD
        +0x00c IdleThread            : Ptr32 _KTHREAD

展开KPRCB结构继续观察可以看到FS:[0x124]指向了KTHREAD结构

实例2:
获取IdleProcess
代码:

kd> dt _KPRCB
nt!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD
   +0x008 NextThread       : Ptr32 _KTHREAD
   +0x00c IdleThread       : Ptr32 _KTHREAD

kd> dt _KTHREAD
nt!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY
   +0x018 InitialStack     : Ptr32 Void
   +0x01c StackLimit       : Ptr32 Void
   +0x020 Teb              : Ptr32 Void
   +0x024 TlsArray         : Ptr32 Void
   +0x028 KernelStack      : Ptr32 Void
   +0x02c DebugActive      : UChar
   +0x02d State            : UChar
   +0x02e Alerted          : [2] UChar
   +0x030 Iopl             : UChar
   +0x031 NpxState         : UChar
   +0x032 Saturation       : Char
   +0x033 Priority         : Char
   +0x034 ApcState         : _KAPC_STATE
kd> dt _KAPC_STATE
nt!_KAPC_STATE
   +0x000 ApcListHead      : [2] _LIST_ENTRY
   +0x010 Process          : Ptr32 _KPROCESS
   +0x014 KernelApcInProgress : UChar
   +0x015 KernelApcPending : UChar
   +0x016 UserApcPending   : UChar

代码:

VOID GetIdleProcess()
{
     PEPROCESS IdleProcess;
     _asm
     {
         mov eax,fs:[0x20] //取KPCRB
         mov eax,[eax+0xC] //取IdleThread
         mov eax,[eax+0x44]//取ApcState->Process
         mov IdleProcess,eax
     }
}

最后贴一张KPCR结构图
附件 92396

上传的图像
文件类型: png 111.png (108.8 KB)
文件类型: png 222.png (45.3 KB)
文件类型: png 333.png (53.7 KB)
Viewing all 9556 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>