您现在的位置: Tracy‘Blog > 博客 > 黑人黑事 > 正文
校园网那些事(五)
 

Chapter 2——破解自身算法

    还记得前面我们hook出来的真实密码么?恩,我们按照对应的关系给0-9建立了一张表格,稍微推导一下算法,可却发现继续不下去了,是啊,数字和字母至少可以用hook给它一一对应起来,可要是用的是汉字呢?要知道,在带有password属性的文本框中是不能输入汉字的。那就意味着不能用hook找出汉字对应的密码咯。当然,老这么用先前的工具去找密码显得太过于繁琐了。于是,我们今天来看一看它到底是通过什么算法加密的。

    其实,这一段是在后面我想弄清楚网络数据包的信息时找到的算法,不过,为了文章的流畅性,就一步步的说过去吧。

还是先来分析下吧:

以下是引用片段:
1.     文件运行首先是读取pppoe.cfg
2.     而后再用3DES解密算法对其解密,得到里面的信息,如账号、密码、自动拨号、保存密码等
3.     在之后就是把这些信息set在UI上
4.     用户点击拨号后,程序先把UI上的信息再次加密保存到pppoe中。
5.     获取本机当前的网卡型号,用于主程序查找已建立的拨号连接(因为那个连接是以网卡信息命名的)。
6.     若找到对应建立的拨号连接,调用rasdial进行拨号,如果没有对应的拨号连接,则自动建立拨号连接,然后再调用rasdial进行拨号。(前面分析过,这个连接是在用户点击拨号后建立的)

    那也就是说,在第六步无论如何都会调用rasdial进行拨号的。传递给rasdial的参数就是我们要找的真实密码,前面我们用hook程序验证了,是加好密了的。那也就是说,如果以上猜测没错的话,在读取文件得到输入的账号密码到调用rasdial中间,肯定有对账号进行加密得到真实密码的地方。

    打开OD,加载程序(脱壳了的,加的是ASPack 2.12,用插件、单步都可以顺利脱掉,这壳只起到压缩资源的作用)。继续用C32asn打开(这软件用习惯了,用它找文本,找导入很是方便),Ctrl+I,搜索rasdial,找到对应的地址,复制到OD中下断。或者,也可以直接在OD命令行下bp RasDialA。用C32Asm另一个作用就是确定是否调用这个API。

    F9,跑起来,然后点击拨号,程序中断在系统领空了。Alt+F9返回。并且对返回地址的上一个Call下断点。因为是它调用的RasDialA。然后Ctrl+F2重新加载程序。F9运行,我们先看看它传递了什么参数。断在了00401CC6 call 处。

    恩,先看看RasDialA函数。

函数原型:
DWORD RasDial(
  LPRASDIALEXTENSIONS  dialExtensions,
  LPTSTR  phoneBookPath ,
  LPRASDIALPARAMS  rasDialParam ,
  DWORD  NotifierType,
  LPVOID  notifier,
  LPHRASCONN  pRasConn );

参数:
dialExtensions:可以被忽略并且可以设置为NULL。
phoneBookPath:可以被忽略并且可以设置为NULL。
rasDialParam:指向RASDIALPARAMS 结构的指针,用来描述 RAS连接的调用参数。调用者必须设置RASDIALPARAMS 结构的 dwSize成员(即结构大小),用sizeof(RASDIALPARAMS)取得大小,防止不同版本的系统取得的大小不同
NotifierType:描述通告程序的参数性质。如果通告程序为NULL,本参数可以忽略,如果非空,则设置本参数0xFFFFFFFF 通过程序是一个句柄,是窗体接收通告程序消息用的。在通告程序进行中,wParam参数指示 RAS连接将要进入的连接状态。当发生错误时lParam里存储错误信息。
Notifier:一个指针,指向窗体句柄,用来接收RasDial的通告事件。如果本参数非空,RasDial为每一个通告事件发送一个windows消息。RasDial调用异步操作:在建立连接之前RasDial立即返回,使用窗体进行进程通信。
pRasConn:一个HRASCONN类型的指针,必须设置HRASCONN 类型变量为空在调用RasDial前。如果RasDial成功,本函数存储一个RAS连接句柄在本参数中。
返回值: 0表示成功。而且本函数存储一个RAS连接的句柄的指针在pRasConn中,非0值表示错误。

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


    也就是说,在调用rasdial时的参数是这六个。而且我们知道,C++是使用_Cdel规范,即:传递的参数是从右到左依次入栈的。也就是说,Arg1就是第一个参数dialExtensions的值。依次类推。我们来看看第三个参数吧。0012EBCC,在数据窗口中跟随。

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;

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

    那么,怎么得到这个信息呢?前面我用dll钩子实现了,今天我们来找找其他的方法。从这个结构体中直接还原出账号密码。先看看这一段有些什么特点,第一个传入的是大小,第二个传入的是拨号实体,也就是我们要进行拨号的那个拨号连接的名称。就是pppoe_的那个,第三个是电话号码,第四个是回拨,第五个是用户名,第六个是密码。


    黄色的是第一个参数,即整个结构体的大小,为041C,与012EBCC相加就得到末地址0012EFE8。红色的就是第二个参数:拨号实体(这个是可以肉眼识别出来的)。

    从首地址看到末地址,很快就可以找出两个可读ascii码,分别是账号和密码。于是,我们用内存注册机也能实现。当然,现在是要找算法。密码出现在:

0012EED4  34 38 63 39 34 39 64 38 65 38 63 39 01 02 00 00  48c949d8e8c9[1]..

    现在我们关注的是,它是怎么来的。于是,对0012EED4处下硬件访问断点,最好是在点击拨号前下(可避免前面对这段空间访问产生的不是自己想要的中断)。结果发现,也不能下断,因为在程序运行过程中会一直对这段空间进行访问,所以,我们只能在00401CC6这个调用拨号的call前面下断点,并且,一直关注这0012EED4这段空间,来缩小范围。经过很多次尝试后,发现程序运行到00401B45时,0012EED4中存放的是未加密的密码。

    而,F8步过这个Call后也并没有发生什么变化。继续F8往下走,先不跟进去,确定了再跟进去。一直到00401BBA处出现了密码。


    我们暂且可以认为,加密段是在00401BBA以上的,至于上到哪里,暂时也不能确定。而运行到00401C1A的时候,真凶出现了。恩,我们来分析一下00401BBA前后这段代码。


    00401B45前面一段和00401BBA后面一段很相似,而且,作用也都是改变0012EED4中的内容,而且没有调用函数,于是我们可以判定它们只是起到转移数据的作用,不是我们要找的,然后00401B45到00401BBA的代码如下:

以下是引用片段:
00401B45  |.  E8 E60A0000   call Tracy.00402630
00401B4A  |.  B9 40000000   mov ecx,40
00401B4F  |.  33C0          xor eax,eax
00401B51  |.  8DBC24 280100>lea edi,dword ptr ss:[esp+128]
00401B58  |.  BE 98254400   mov esi,Tracy.00442598                        ;,   ASCII "032593"
00401B5D  |.  F3:AB         rep stos dword ptr es:[edi]
00401B5F  |.  A1 94254400   mov eax,dword ptr ds:[442594]
00401B64  |.  8D7C24 28     lea edi,dword ptr ss:[esp+28]
00401B68  |.  8BC8          mov ecx,eax
00401B6A  |.  50            push eax
00401B6B  |.  8BD1          mov edx,ecx
00401B6D  |.  8D4424 2C     lea eax,dword ptr ss:[esp+2C]
00401B71  |.  C1E9 02       shr ecx,2
00401B74  |.  F3:A5         rep movs dword ptr es:[edi],dword ptr ds:[esi>
00401B76  |.  8BCA          mov ecx,edx
00401B78  |.  50            push eax
00401B79  |.  83E1 03       and ecx,3
00401B7C  |.  F3:A4         rep movs byte ptr es:[edi],byte ptr ds:[esi]
00401B7E  |.  E8 AD0A0000   call Tracy.00402630
00401B83  |.  A1 94254400   mov eax,dword ptr ds:[442594]
00401B88  |.  83C4 10       add esp,10
00401B8B  |.  33F6          xor esi,esi
00401B8D  |.  3BC3          cmp eax,ebx
00401B8F  |.  8DBC24 200100>lea edi,dword ptr ss:[esp+120]
00401B96  |.  7E 22         jle short Tracy.00401BBA
00401B98  |>  33C9          /xor ecx,ecx                                  ;  将密码以十六进制输出
00401B9A  |.  8A4C34 20     |mov cl,byte ptr ss:[esp+esi+20]
00401B9E  |.  51            |push ecx
00401B9F  |.  68 84B44300   |push Tracy.0043B484                          ;  ASCII "%02x"
00401BA4  |.  57            |push edi
00401BA5  |.  E8 281D0100   |call Tracy.004138D2
00401BAA  |.  A1 94254400   |mov eax,dword ptr ds:[442594]
00401BAF  |.  83C4 0C       |add esp,0C
00401BB2  |.  83C7 02       |add edi,2
00401BB5  |.  46            |inc esi
00401BB6  |.  3BF0          |cmp esi,eax
00401BB8  |.^ 7C DE         \jl short Tracy.00401B98
00401BBA  |>  8DBC24 200100>lea edi,dword ptr ss:[esp+120]                ;  得到密码放入EDI中

    红色那一部分的“%02x”让我联想到C里面的格式转换,而且,我们也分析得出,这一段的确是用来把字符串格式化的。所以,范围再次缩小。整个这一段也就只有三个call,被我们排除了一个,其他两个都是call的一个函数,说不定就是算法段呢。我们跟进去看看。直接在00401B45处敲下enter键。看到了下面的代码。

以下是引用片段:
00402630  /$  55            push ebp
00402631  |.  8B6C24 0C     mov ebp,dword ptr ss:[esp+C]
00402635  |.  85ED          test ebp,ebp
00402637  |.  57            push edi
00402638  |.  7F 05         jg short Tracy.0040263F
0040263A  |.  5F            pop edi
0040263B  |.  33C0          xor eax,eax
0040263D  |.  5D            pop ebp
0040263E  |.  C3            retn
0040263F  |>  8B7C24 0C     mov edi,dword ptr ss:[esp+C]
00402643  |.  85FF          test edi,edi
00402645  |.  75 05         jnz short Tracy.0040264C
00402647  |.  5F            pop edi
00402648  |.  33C0          xor eax,eax
0040264A  |.  5D            pop ebp
0040264B  |.  C3            retn
0040264C  |>  56            push esi
0040264D  |.  33F6          xor esi,esi
0040264F  |.  85ED          test ebp,ebp
00402651  |.  7E 3F         jle short Tracy.00402692
00402653  |>  8A0C3E        /mov cl,byte ptr ds:[esi+edi]                 ;  取密码第一位字符
00402656  |.  8AC1          |mov al,cl                                    ;  密码第一位字符赋值给AL
00402658  |.  8AD1          |mov dl,cl                                    ;  密码第一位字符赋值给DL
0040265A  |.  C0E8 02       |shr al,2                                     ;  AL向右移动2位
0040265D  |.  24 20         |and al,20                                    ;  AL与上20
0040265F  |.  80E2 40       |and dl,40                                    ;  密码第一位与上40
00402662  |.  0AC2          |or al,dl
00402664  |.  8AD1          |mov dl,cl                                    ;  密码第一位字符赋值给DL
00402666  |.  C0E8 02       |shr al,2                                     ;  AL向右移动2位
00402669  |.  80E2 20       |and dl,20                                    ;  与20
0040266C  |.  0AC2          |or al,dl                                     ;  AL或DL
0040266E  |.  8AD1          |mov dl,cl                                    ;  密码第一位字符赋值给DL
00402670  |.  D0E8          |shr al,1                                     ;  AL向右移动1位
00402672  |.  80E2 02       |and dl,2                                     ;  DL与上2
00402675  |.  0AC2          |or al,dl                                     ;  AL或DL
00402677  |.  8AD1          |mov dl,cl                                    ;  密码第一位字符赋值给DL
00402679  |.  80E2 1C       |and dl,1C                                    ;  密码第一位与上1C
0040267C  |.  C0E1 05       |shl cl,5                                     ;  CL左移5位
0040267F  |.  0AD1          |or dl,cl                                     ;  DL与上CL
00402681  |.  D0E8          |shr al,1                                     ;  AL向右移动1位
00402683  |.  C0E2 02       |shl dl,2                                     ;  DL向左移动2位
00402686  |.  0AC2          |or al,dl                                     ;  huo
00402688  |.  74 03         |je short Tracy.0040268D
0040268A  |.  88043E        |mov byte ptr ds:[esi+edi],al                 ;  填充到原来的地方
0040268D  |>  46            |inc esi                                      ;  字符标记
0040268E  |.  3BF5          |cmp esi,ebp                                  ;  当ESI等于EBP的时候,代表所有的字符都计算完了
00402690  |.^ 7C C1         \jl short Tracy.00402653                      ;  循环
00402692  |>  5E            pop esi
00402693  |.  5F            pop edi
00402694  |.  B8 01000000   mov eax,1
00402699  |.  5D            pop ebp
0040269A  \.  C3            retn

    而且,有没觉得红色的那段代码太漂亮、太独特了。或许,它们就是我们要找的算法呢。恩,下好断点,OD重载。再来一次,看传进去的是些什么参数。又对这些参数做了什么。

   我们发现,在00401B45前面总共只有两个push,可能,传进去的参数也就只有两个吧,看堆栈窗口。


    恩,传进去的是原始密码,和密码的长度。好像,我们越来越接近我们的答案了哈。先不进去,数据窗口跟随12E9CC,F8步过,看看有什么变化。


    嗯?变了一半,那是不是说,另外一半是在后面那个call里面弄出来的呢?答案是肯定的,于是,分析上面的那段算法吧,注解也已经写上去了。其实就是一段移位算法,可逆向的,也就是可是反向解密。于是,先写下它的加密算法用C表示如下:

KEY[i]=((((((((pwd[i]>>2)&0X20)|(pwd[i]&0X40))>>2)|(pwd[i]&0X20))>>1)|(pwd[i]&0X2))>>1)|(((pwd[i]&0X1C)|(pwd[i]<<5))<<2);

    然后呢,解密算法,程序中可能会有也可能没有,至少,我们不知道它在什么地方用到解密,由于第一次接触这些,不知道如何写出解密算法。

    发帖求助:http://bbs.pediy.com/showthread.php?t=157538,然后得到了好心人的解答方法,自己再在草稿纸上画了画,于是写下了解密算法。

    CON[i]=((pwd[i]&0X70)>>2)|((pwd[i]&0X80)>>7)|((pwd[i]&0X02)<<6)|((pwd[i]&0X04)<<4)|((pwd[i]&0X08)<<2)|((pwd[i]&0X01)<<1);

    这个算法,后面的利用中也用到了。

    所以,我们就成功的解决了密码是英文的问题,也解决了对中文加密的问题(后面有对中文加密的实例)。

    于是,Chapter1中,获取真实密码那一段switch case可替换为:

    KEY[i]=((((((((pwd[i]>>2)&0X20)|(pwd[i]&0X40))>>2)|(pwd[i]&0X20))>>1)|(pwd[i]&0X2))>>1)|(((pwd[i]&0X1C)|(pwd[i]<<5))<<2);

    恩,就写到这里吧,近三个小时了,手都敲痛了。后面估计还有那么四到五章,分别是MD5、网络校验、和一个系统的编写、以及最后的总结。

 

发表评论(6)
1楼 小宠  发表于  2013-5-31 15:20:13
不错 利用windows api是最容易破解软件的 windows的消息映射就是为破解准备的
2楼 小宠  发表于  2013-5-31 15:01:10
我电脑是ubuntu操作系统,希望能帮下忙,破解下真实密码,我好直接用pppoe拨号,谢谢!
3楼 houjoutan  发表于  2013-3-26 18:23:50
http://www.sogou.com/websnapshot?&url=http%3A%2F%2Ftieba.baidu.com%2Fp%2F1853093840&did=60d2f4fe0275d790-0e5cddc599ccfe14-10ad86e094d24b366d87417f60cf4a5a&k=2b22fa2681a6499ba7afb3c1c7a6d76a&encodedQuery=%BA%FE%C4%CF%C9%E6%CD%E2%BE%AD%BC%C3%D1%A7%D4%BA%D0%A3%D4%B0%CD%F8%C3%E2%BA%FB%B5%FB%2C%C8%C3%C2%B7%D3%C9%C6%F7%B9%B2%CF%ED%CD%F8%C2%E7&query=%BA%FE%C4%CF%C9%E6%CD%E2%BE%AD%BC%C3%D1%A7%D4%BA%D0%A3%D4%B0%CD%F8%C3%E2%BA%FB%B5%FB%2C%C8%C3%C2%B7%D3%C9%C6%F7%B9%B2%CF%ED%CD%F8%C2%E7&&p=40040100&dp=1&w=01020400&m=0&st=0 話說是不是路由器技術被非法利用了。
[博主回复]  我知道这个人,并且,警告过他,随他去吧。
4楼 houjoutan  发表于  2013-3-10 10:57:39
pppoe密码里面有两个ASCII控制字符,在openwrt或者ddwrt或者tomato路由器上面只需要写成转意字符就行了 一般是 \1\2
[博主回复]  是十六进制的0001 0002,而且,不是控制字符,是1.2.0升级到1.2.9后为了防止用路由而添加的两个不便手动输入的字符。
5楼 houjoutan  发表于  2013-3-10 10:56:13
而且发现172.31.15.2这个IP地址是由学校定的。因为下载了其他学校的客户端IP不同
[博主回复]  这个是服务器地址,肯定每个学校都不同撒
6楼 houjoutan  发表于  2013-3-10 10:54:27
目测关键还是那个坑爹的发往172.31.15.2里面有验证信息,如果可以解析这两个数据包,然后编写软件自动产生,就能用路由器了。。。昨天挂路由3小时,账号挂起5小时- -坑爹呢?反正发现没有别的地方了,只有172.31.15.2这两个数据包里面不知道卖 的什么 丹药
[博主回复]  那两个数据包,解密后,可以用winhex查看内存找到。发送的是:账号+时间+控制字符。目的是为了查看账户信息,比如余额。收到的是:你剩余的余额是……还有就是一些控制字符,比如,弹出网页,弹出窗口,等。
姓名 *
电子邮件
QQ
评论内容 *
验证码 *图片看不清?点击重新得到验证码请输入图片后链接字符‘a’