您现在的位置: Tracy‘Blog > 博客 > 一些破文 > 正文
再窥pppoe拨号客户端1.2.9

这些天看《加密解密3》,时不时的总会想起校园网的pppoe拨号客户端。虽然,自己已经成功的破解了它,也知道它的原理与实现方法,但总觉得,从pppoe.cfg中读取内容还原出真实密码那一块还没搞清楚它的算法,还原到的密码到得到真实密码的算法,虽然自己知道了转换过程,但是还没有真正的跟踪出这段算法。于是,今天又翻出以前的笔记,重新开始跟踪。

拿出od,载入客户端主程序。我们先来分析一下程序运行的过程。

 

1.启动

2.  →判断主程序文件夹下是否存在pppoe.cfg

3.      →存在则检测是否勾选保存密码

4.          →是  则从文件中读取内容还原手动输入的账号密码

5.          →否  跳过

6.      →不存在则显示空白。跳过读文件代码段

7.  →检测是否勾选自动拨号

8.      →是  则将用户名密码读取到缓冲区,将密码加密得到真实密码之后拨号

9.      →否  无任何动作,等待用户操作

 

由上可以得出,如果我们要跟踪从pppoe.cfg还原密码过程,我们应该在第四步下断点,在他还原前,断下,然后再跟踪。如果我们要跟踪从输入密码到真实密码加密的过程,我们应该在第八步下断点进行跟踪。

我们以前是在读取文件的时候下断点进行跟踪,现在我们换一种思路,在保存的时候来跟踪试试。另外,虽然知道了怎么进行密码到真实密码的过程,但是我们还是来跟踪一下,所以,我们先下拨号断点,在拨号时他调用的是RasDialA,所以我们来下端断点bp RasDialA

先还是来补充一下这个对这个函数的了解吧。

函数原型:

DWORD RasDial(

  LPRASDIALEXTENSIONS dialExtensions,

  LPTSTR phoneBookPath ,

  LPRASDIALPARAMS rasDialParam ,

  DWORD NotifierType,

  LPVOID notifier,

  LPHRASCONN pRasConn );

参数

  dialExtensions

  本参数可以被忽略并且可以设置为NULL,Windows CE,RasDial 总是使用RASDIALEXTENSIONS 当做默认选项。

  phoneBookPath

  本参数可以被忽略并且可以设置为NULL,通过电话簿存储进行拨号上网注册,而不是通过电话簿文件。

  rasDialParam

  一个指向RASDIALPARAMS 结构的指针,用来描述 RAS连接的调用参数。调用者必须设置RASDIALPARAMS 结构的 dwSize成员(即结构大小),用sizeof(RASDIALPARAMS)取得大小,防止不同版本的系统取得的大小不同

  NotifierType

  描述通告程序的参数性质。如果通告程序为NULL,本参数可以忽略,如果非空,则设置本参数0xFFFFFFFF 通过程序是一个句柄,是窗体接收通告程序消息用的。在通告程序进行中,wParam参数指示 RAS连接将要进入的连接状态。当发生错误时lParam里存储错误信息。

  notifier

  一个指针,指向窗体句柄,用来接收RasDial的通告事件。如果本参数非空,RasDial为每一个通告事件发送一个windows消息。RasDial调用异步操作:在建立连接之前RasDial立即返回,使用窗体进行进程通信。

  如果本参数被设置为:NULL,RasDial 调用同步操作:RasDial不立即返回,直到连接成功或者连接失败。

  如果本参数非空,在调用RasDial之后,窗体通知会在任何时候出现。当下列事件发生时通知结束:

  连接被建立,换句话说,RAS的连接状态是RASCS_Connected

  连接失败,换句话说,dwError 非零

  RasHangUp在连接时被调用

  在RasDial最初被调用时,在线程获取上下文时产生回调通知

  pRasConn

  一个HRASCONN类型的指针,必须设置HRASCONN 类型变量为空在调用RasDial前。如果RasDial成功,本函数存储一个RAS连接句柄在本参数中。

  返回值:

  0表示成功。而且本函数存储一个RAS连接的句柄的指针在pRasConn

0值表示错误。

 

 

       我们od中下好断点后,直接F9运行。发现,程序被断下来了。Alt+F9返回程序领空。然后网上翻,找到00401CC6下断点。重新载入,运行,在00401CC6断下,之后我们可以在堆栈窗口中看到这些:

再窥pppoe拨号客户端1.2.9

也就是说,在调用rasdial时的参数是这六个。而且我们知道,C++是使用_Cdel规范,

即:传递的参数是从右到左依次入栈的。也就是说,Arg1就是第一个参数dialExtensions的值。依次类推。

我们来看看第三个参数吧。0012E314,在数据窗口中跟随

它就是我们的RASDIALPARAMSA结构如下:

 

typedef struct _RASDIALPARAMS {

  DWORD     dwSize;

  TCHAR     szEntryName[RAS_MaxEntryName + 1];

  TCHAR     szPhoneNumber[RAS_MaxPhoneNumber + 1];

  TCHAR     szCallbackNumber[RAS_MaxCallbackNumber + 1];

  TCHAR     szUserName[UNLEN + 1];

  TCHAR     szPassword[PWLEN + 1];

  TCHAR     szDomain[DNLEN + 1];

  DWORD     dwSubEntry;

  ULONG_PTR dwCallbackId;

  DWORD     dwIfIndex;

} RASDIALPARAMS, *PRASDIALPARAMS;

 

其中szUserNameszPasswordADSL账号和密码,也是我们需要截获的数据。

那么,怎么得到这个信息呢?前面我用dll钩子实现了,今天我们来找找其他的方法。从这个结构体中直接还原出账号密码。好像有点不可能。

那么,我们就跟进这个call  看看会发生什么。

来到系统领空。之后,一直单步,在走过的第五个call的地方,发现了我们输入的用户名:

 

再窥pppoe拨号客户端1.2.9

 

那么,密码是不是就在后面呢?

      终于,在76E0C0BA    E8 BCF7FFFF     call rasapi32.RasDialW处,我们发现,它又调用了RasDialW。至于这个WA有什么区别,大家自己百度吧。

看堆栈窗口。

 

再窥pppoe拨号客户端1.2.9

 

也有六个参数,我们进数据窗口跟随看看。

0012D008  0012DEA4  UNICODE "c8c8c8c8c8c8"

 

我们看到了真实密码。所以,可用内存注册机得到真实密码。

 

 上面个的过程我们就可以得到我们想要的真实密码了。

 

 

===================从文件还原账号密码问题:=====================

 

       我们在来跟一下我们说的另一个问题吧,就是。下CreateFileA断点。然后跟踪

 在

0041CC24    FF15 C4014300   call dword ptr ds:[<&kernel32.CreateFileA>]     ;

创建一个新的pppoe.cfg,但是里面没有数据

 

0041CC45    FF15 64014300   call dword ptr ds:[<&kernel32.GetFileType>]     ;

得到文件类型

 

0041CC4B    85C0            test eax,eax                                    ;

判断返回值是否为0

 

0041CC4D    75 09           jnz short 11.0041CC58

0041CC4F    56              push esi

0041CC50    FF15 BC014300   call dword ptr ds:[<&kernel32.CloseHandle>]     ;

kernel32.CloseHandle

0041CC56  ^ EB D8           jmp short 11.0041CC30

0041CC58    83F8 02         cmp eax,2                                       ;

返回值为2为正常磁盘文件

0041CC6E    E8 96FBFFFF     call 11.0041C809                                ;

可能为密码算法段

 

继续跟踪

00402B82   |83C4 08         add esp,8

00402B85   |43              inc ebx

00402B86   |3BDE            cmp ebx,esi

00402B88  ^|7C E9           jl short 11.00402B73

00402B8A   \57              push edi

00402B8B    E8 E40D0100     call 11.00413974                                ;

这个call里面有写文件的过程

 

可以跟踪得到如下数据,可以证明已经将明文转化为密文了。这段循环,是将密文的每

两个数据取出来,然后进行一系列的算法,或者是,以某一特定的结构转化存放在内存

中。然后调用后面这个call将数据写入pppoe.cfg中。

 

004139B5    E8 B14B0000     call 11.0041856B                                ;

这个call中已经写入文件

 

00418587    8B46 08         mov eax,dword ptr ds:[esi+8]                    ;

加密后的数据起始段放入eax

0041858A    8B3E            mov edi,dword ptr ds:[esi]                      ;

加密后的数据结束段放入edi

 

 

0041BD3A    FF15 18024300   call dword ptr ds:[<&kernel32.WriteFile>]       

; kernel32.WriteFile

调用writefile文件,实现写文件。参数如下:

0012EDB4   00000224  $[1]..  |hFile = 00000224 (window)

0012EDB8   00D5A1D8  ?   |Buffer = 00D5A1D8

0012EDBC   00000027  '...  |nBytesToWrite = 27 (39.)

0012EDC0   0012F1DC  .  |pBytesWritten = 0012F1DC

0012EDC4   00000000  ....  \pOverlapped = NULL

 

可以看出,要写入文件的信息存放在00D5A1D8这个缓冲区中。

 

我在回到前面那个27次循环的地方,看看它是否往这个缓冲区中写入了数据。

 

可以知道前面的27次循环,实际上就是搬运的过程。从0012F360搬运到00D5A1D8缓冲。

 

那么他的转换过程应该在从窗体读取文本到00402B71之间。我们再下GetWindowTextA

试试。

 

0042A004    FF15 3C054300   call dword ptr ds:[<&USER32.GetWindowTextA>]    

; 得到用户名

0042A00A    8B4D 10         mov ecx,dword ptr ss:[ebp+10]                   

; ecx中放入输入的用户名和密码的地址、

 

00402B71

 

 

0012FD6C  00E98520  ASCII "Tracy"

0012FD70  00E98570  ASCII "111111"

 

 

00407530    E8 EBABFFFF     call 1_2_9?00402120

 

 

0012F184  2B66A6DC

0012F188  A7D8AFEE

0012F18C  AE09957F

0012F190  C011BA0D

0012F194  83E1753A

0012F198  04CA2608

0012F19C  86154D09

0012F1A0  EC8AA5E5

0012F1A4  3A790D3F

0012F1A8  0C5467B8

每次存放密文的地方都是这两个地方。。。我们接着看。

 

0012F360  2B66A6DC

0012F364  A7D8AFEE

0012F368  AE09957F

0012F36C  C011BA0D

0012F370  83E1753A

0012F374  04CA260, 8

0012F378  86154D09

0012F37C  EC8AA5E5

0012F380  3A790D3F

0012F384  0C5467B8

 

终于,在这个call里面。往那两个地址的一个里面写入的数据,到

00402A42    BF A0284400     mov edi,1_2_9?004428A0                         

; ASCII "Tracy"

的时候

0012F360附近出现了数据说明。算法就在这个附近

 

在这个call里面已经全部生成了。

00402B44    E8 A70D0000     call 1_2_9?004038F0

 

所以,我们的跟踪有目的性了。

 

 

1.下面这段代码实现的功能是:

0012F18C中存放用户名长度。然后在012F190中存放用户名各字母的ascii码。

00402A42    BF A0284400     mov edi,1_2_9?004428A0                         

; ASCII "Tracy"

00402A47    83C9 FF         or ecx,FFFFFFFF

00402A4A    33C0            xor eax,eax

00402A4C    BE A0284400     mov esi,1_2_9?004428A0                          

; ASCII "Tracy"

00402A51    F2:AE           repne scas byte ptr es:[edi]

00402A53    F7D1            not ecx                                         

; 得到用户名长度

00402A55    49              dec ecx

00402A56    BF A0284400     mov edi,1_2_9?004428A0                         

; ASCII "Tracy"

00402A5B    898C24 18010000 mov dword ptr ss:[esp+118],ecx

00402A62    83C9 FF         or ecx,FFFFFFFF

00402A65    F2:AE           repne scas byte ptr es:[edi]

00402A67    F7D1            not ecx

00402A69    49              dec ecx

00402A6A    8DBC24 1C010000 lea edi,dword ptr ss:[esp+11C]

00402A71    8BD1            mov edx,ecx

00402A73    C1E9 02         shr ecx,2

00402A76    F3:A5           rep movs dword ptr es:[edi],dword ptr ds:[esi]

00402A78    8BCA            mov ecx,edx

00402A7A    83E1 03         and ecx,3

00402A7D    F3:A4           rep movs byte ptr es:[edi],byte ptr ds:[esi]

00402A7F    BF A0284400     mov edi,1_2_9?004428A0                         

; ASCII "Tracy"

00402A84    83C9 FF         or ecx,FFFFFFFF

00402A87    F2:AE           repne scas byte ptr es:[edi]

00402A89    F7D1            not ecx

00402A8B    49              dec ecx

00402A8C    BF A0284400     mov edi,1_2_9?004428A0                         

; ASCII "Tracy"

00402A91    8D940C 1C010000 lea edx,dword ptr ss:[esp+ecx+11C]

00402A98    83C9 FF         or ecx,FFFFFFFF

00402A9B    F2:AE           repne scas byte ptr es:[edi]

00402A9D    F7D1            not ecx

00402A9F    49              dec ecx

 

 

 

2.下面这段代码实现的功能是:

0012F195中放入密码长度,然后在0012F199中放入密码的ascii码。

00402AA0    BF 98254400     mov edi,1_2_9?00442598                         

; ASCII "111111"

00402AA5    8BD9            mov ebx,ecx

00402AA7    83C9 FF         or ecx,FFFFFFFF

00402AAA    83C3 0C         add ebx,0C

00402AAD    F2:AE           repne scas byte ptr es:[edi]

00402AAF    F7D1            not ecx

00402AB1    49              dec ecx

00402AB2    BF 98254400     mov edi,1_2_9?00442598                         

; ASCII "111111"

00402AB7    890A            mov dword ptr ds:[edx],ecx

00402AB9    83C9 FF         or ecx,FFFFFFFF

00402ABC    83C2 04         add edx,4

00402ABF    BE 98254400     mov esi,1_2_9?00442598                         

; ASCII "111111"

00402AC4    F2:AE           repne scas byte ptr es:[edi]

00402AC6    F7D1            not ecx

00402AC8    49              dec ecx

00402AC9    8BFA            mov edi,edx

00402ACB    8BC1            mov eax,ecx

00402ACD    6A 00           push 0

00402ACF ,, ; &nb, sp; C1E9, 02         shr ecx,2

00402AD2    F3:A5           rep movs dword ptr es:[edi],dword ptr ds:[esi]

00402AD4    8BC8            mov ecx,eax

00402AD6    33C0            xor eax,eax

00402AD8    83E1 03         and ecx,3

00402ADB    6A 0F           push 0F

00402ADD    F3:A4           rep movs byte ptr es:[edi],byte ptr ds:[esi]

00402ADF    BF 98254400     mov edi,1_2_9?00442598                         

; ASCII "111111"

00402AE4    83C9 FF         or ecx,FFFFFFFF

00402AE7    F2:AE           repne scas byte ptr es:[edi]

00402AE9    F7D1            not ecx

00402AEB    49              dec ecx

00402AEC    BF 98254400     mov edi,1_2_9?00442598                         

; ASCII "111111"

00402AF1    03D1            add edx,ecx

00402AF3    83C9 FF         or ecx,FFFFFFFF

00402AF6    F2:AE           repne scas byte ptr es:[edi]

00402AF8    F7D1            not ecx

00402AFA    49              dec ecx

 

3.判断是否选上保存密码。如果是,则在0012F19F处附上01,没有则填充00

00402AFB    68 E0B04300     push 1_2_9?0043B0E0                            

; ASCII "0herolibamtium0"

00402B00    8D740B 04       lea esi,dword ptr ds:[ebx+ecx+4]                

; 将长度放入esi

00402B04    8A1D 642F4400   mov bl,byte ptr ds:[442F64]

00402B0A    84DB            test bl,bl

00402B0C    0F95C0          setne al

00402B0F    8902            mov dword ptr ds:[edx],eax

 

4.判断是否选上自动连接。如果是,则在0012F1A3处写入01.没有则填充00

00402B11    8A1D 652F4400   mov bl,byte ptr ds:[442F65]

00402B17    83C2 04         add edx,4

00402B1A    83C6 04         add esi,4

00402B1D    33C0            xor eax,eax

00402B1F    8D8C24 1C010000 lea ecx,dword ptr ss:[esp+11C]

00402B26    84DB            test bl,bl

00402B28    0F95C0          setne al

00402B2B    8902            mov dword ptr ds:[edx],eax

 

5.0012F1A7赋值为00

00402B30    8942 04         mov dword ptr ds:[edx+4],eax

 

6.将长度密文长度放入0012F184中。此例中为27.

00402B3D    89B424 28010000 mov dword ptr ss:[esp+128],esi

 

7.算法部分在这个call里面

00402B44    E8 A70D0000     call 1_2_9?004038F0

 

这个为算法循环。

 

 

00403DFD    8BC8            mov ecx,eax

00403DFF    8A1C38          mov bl,byte ptr ds:[eax+edi]

00403E02    C1F9 03         sar ecx,3

00403E05    8D3411          lea esi,dword ptr ds:[ecx+edx]

00403E08    8BC8            mov ecx,eax

00403E0A    83E1 07         and ecx,7

00403E0D    D2E3            shl bl,cl

00403E0F    8A0E            mov cl,byte ptr ds:[esi]

00403E11    0ACB            or cl,bl

00403E13    40              inc eax

00403E14    3BC5            cmp eax,ebp

00403E16    880E            mov byte ptr ds:[esi],cl

00403E18  ^ 7C E3           jl short 1_2_9?00403DFD

 

得到每一小段的算法,

 

这个循环得到整个一大段的算法:

0040397E    53              push ebx

0040397F    68 6C314400     push 1_2_9?0044316C                            

; 看看每次的是否一样

00403984    57              push edi

00403985    56              push esi

00403986    E8 C5000000     call 1_2_9?00403A50                             

; 前面一段密文的第一次加密

0040398B    8B4424 38       mov eax,dword ptr ss:[esp+38]

0040398F    50              push eax

00403990    68 6C344400     push 1_2_9?0044346C

00403995    56              push esi

00403996    56              push esi

00403997    E8 B4000000     call 1_2_9?00403A50                            

; 前面一段密文的第二次加密

0040399C    53              push ebx

0040399D    68 6C314400     push 1_2_9?0044316C

004039A2    56              push esi

004039A3    56              push esi

004039A4    E8 A7000000     call 1_2_9?00403A50                            

; 前面一段密文的第三次加密

004039A9    83C4 30         add esp,30

004039AC    83C6 08         add esi,8

004039AF    83C7 08         add edi,8

004039B2    4D              dec ebp

004039B3  ^ 75 C9           jnz short 1_2_9?0040397E                      &nb, sp; <, /o:p>

; 循环直到八个地址段全部加密完成

 

 

 

但是分析不出来,也没能写出解密程序。所以,希望大牛们给点提示啊。

&nbs, p;<, /o:p>

马上就要准备考研了。得放下技术一段时间了。

 

加油,努力! 

发表评论(1)
1楼 markmisss  发表于  2012-3-14 1:28:33
不要老是要人家百度。既然作为一篇技术文章,那么从头至尾要详细的解说其中的要点和来龙去脉,所以很多书都有注释的。很仔细的看了你的文章,发现语言不过精炼,言语累赘非常多,这样会影响读者的情绪,使人厌烦。并且,作为技术帖不光只是给懂行的人看,如果是外行人也看懂了,那才是经典。
[博主回复]  不是我故意含糊,一些触犯到机构机密的东西不好随意发布,否则,遭殃的,迟早是自己。其实你要的那些东西,我都已经做好了。
姓名 *
电子邮件
QQ
评论内容 *
验证码 *图片看不清?点击重新得到验证码请输入图片后链接字符‘a’