知识屋:更实用的电脑技术知识网站
所在位置:首页 > 网络安全 > 技术文献

还原精灵密码算法分析

发布时间:2011-07-26 08:32:03作者:知识屋

 

还原精灵密码算法分析

  作 者: figo

  时 间: 2006-05-31 14:47

  链 接: http://bbs.pediy.com/showthread.php?threadid=26616[/url]

  详细信息:

  【文章标题】 : 还原精灵密码算法分析

  【调试环境】 : WINXP OllyDbg1.10 PEID 0.94

  【软件名称】 : 还原精灵

  【破解目的】 : 研究算法分析

  【加密方式】 : 加壳,未知壳

  【文章作者】 : figo

  【作者声明】 : 只为研究算法分析,没有其他目的. 请勿用与恶意破坏等非法用途,

  否则给自己或他人带来严重后果,概与本人无关.失误之处恳请批评指正,

  或有更好的方法或者技巧,欢迎互相交流. 版主若觉此帖违规,请删除,勿封我ID.

  【破解过程】 :

  还原精灵是一款很优秀的软件,它能够记录下一切对硬盘的写操作,

  不论您对硬盘进行拷贝还是移动删除甚至是格式化分区等操作,只要一重新启动,

  一切都会恢复到这个操作之前的状态,所以被广泛应用在学校机房和网吧等公共场合的

  电脑上. 但是装还原精灵的用户如果忘记了密码就成麻烦事了,想卸掉要密码,想删也删不掉.

  记得网上有一种能删除还原精灵的软件,是风般的男人(我也不知道他的真名,呵呵)编写的.

  我个人是极不赞成用这种方法,因为这软件太 "野蛮" 了,它在取得 RING0 后,直接用硬盘 IO 把

  原来的 BOOT 扇区强制写入物理 0 磁道 1 扇区.对 5.5 以上的版本会造成系统崩溃,

  因为还原精灵为了与 NT/2000/XP 兼容,会替换一些驱动程序.

  希望本文能对那些想卸载还原精灵而又忘记密码的用户带来帮助.

  还原精灵早期版本密码加密算法很简单,甚至不加密直接明码比较.

  5.5 版本加密算法是: 密文 = 密码 XOR A5A5A5A5A5A5A5A5H

  6.0 版本的加密算法比较复杂,下面来分析一下

  该程序加了壳,是弱壳,用OD 手动脱了

  入口点是 004318A4.

  下面列出程序一些关键代码片段(用 OD 分析的),至于怎么跟踪得来,由于篇幅关系暂不讨论

  本文只讨论密码算法和解密器的编写.

  0040160E . E8 B9F70200 call

  00401613 . 8D86 18020000 lea eax, [esi+218]

  00401619 . 8BCE mov ecx, esi

  0040161B . 50 push eax

  0040161C . E8 EF010000 call 00401810 ; --------> 验证密码子程序

  00401621 . 85C0 test eax, eax

  00401623 . 0F85 D6000000 jnz 004016FF ; ----------> 关键跳转

  00401629 . 8D4C24 0C lea ecx, [esp+C]

  0040162D . E8 4CF70200 call

  00401632 . 8D4C24 08 lea ecx, [esp+8]

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  跟进 CALL 00401810

  代码如下:

  00401839 |. E8 A0F50200 call

  0040183E |. 8BCB mov ecx, ebx

  00401840 |. 8BF0 mov esi, eax

  00401842 |. 8BC1 mov eax, ecx

  00401844 |. 8D7C24 10 lea edi, [esp+10]

  00401848 |. C1E9 02 shr ecx, 2

  0040184B |. F3:A5 rep movs dword ptr es:[edi], dword p>

  0040184D |. 8BC8 mov ecx, eax

  0040184F |. 83E1 03 and ecx, 3

  00401852 |. F3:A4 rep movs byte ptr es:[edi], byte ptr>

  00401854 |. 8D4C24 10 lea ecx, [esp+10]

  00401858 |. 51 push ecx

  00401859 |. E8 02490100 call 00416160

  注意这个CALL,入栈的是密码原文地址.

  把它步过,看看各个寄存器和密码原文有何变化.

  我们可以看到密码原文变成密文.

  把这个CALL 置断点,重新来过

  跟进这个CALL

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  00416160 /$ 8B4424 04 mov eax, [esp+4]

  00416164 |. 6A 20 push 20 ; Arg3 = 00000020

  00416166 |. 50 push eax ; Arg2 = 密码原文

  00416167 |. 68 80254400 push 00442580 ; Arg1 = 00442580 ASCII "NJYZ-RG-60-TT-60"

  0041616C |. E8 1FFFFFFF call 00416090 ; -----------------------> 转换密文子程序

  00416171 |. 83C4 0C add esp, 0C

  00416174 . C3 retn

  注意这个CALL 的3个参数

  第一个参数是指向一个字符串 "NJYZ-RG-60-TT-60"

  第二个参数是指向密码原文

  第三个参数是一个常数 00000020H

  不难猜出这个CALL 是一个明文转换密文的子程序

  跟进去看看,下面这段代码就是密码转换算法

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  00416090 /$ 55 push ebp

  00416091 |. 8BEC mov ebp, esp

  00416093 |. 8B45 10 mov eax, [ebp+10]

  00416096 |. 53 push ebx

  00416097 |. 56 push esi

  00416098 |. 57 push edi

  00416099 |. 85C0 test eax, eax

  0041609B |. 7E 5D jle short 004160FA

  0041609D |. 60 pushad

  0041609E |. 8B75 08 mov esi, [ebp+8]

  004160A1 |. 8B7D 0C mov edi, [ebp+C]

  004160A4 |. 57 push edi

  004160A5 |. 8B1F mov ebx, [edi]

  004160A7 |. 8B4F 04 mov ecx, [edi+4]

  004160AA |. 33C0 xor eax, eax

  004160AC |. BA B979379E mov edx, 9E3779B9

  004160B1 |. 66:BF 2000 mov di, 20

  这时候各个寄存器:

  ESI 指向字符串 "NJYZ-RG-60-TT-60"

  EDX 常数 9E3779B9

  EBX 密码明文前4个字节

  ECX 密码明文后4个字节

  DI 常数 0020H

  大家应该可以下面的代码看出:

  密码密文是把明文和字符串"NJYZ-RG-60-TT-60"和常数 9E3779B9 进行加密

  其中密码的前4字节和字符串"NJYZ-RG-"加密

  密码的后4字节和字符串"60-TT-60"加密

  而且密码的前后4字节在每次加密循环都相互加密

  004160B5 |> 03C2 /add eax, edx ;--------------->加密循环

  004160B7 |. 8BE9 |mov ebp, ecx

  004160B9 |. C1E5 04 |shl ebp, 4

  004160BC |. 03DD |add ebx, ebp

  004160BE |. 8B2E |mov ebp, [esi]

  004160C0 |. 33E9 |xor ebp, ecx

  004160C2 |. 03DD |add ebx, ebp

  004160C4 |. 8BE9 |mov ebp, ecx

  004160C6 |. C1ED 05 |shr ebp, 5

  004160C9 |. 33E8 |xor ebp, eax

  004160CB |. 03DD |add ebx, ebp

  004160CD |. 035E 04 |add ebx, [esi+4]

  004160D0 |. 8BEB |mov ebp, ebx

  004160D2 |. C1E5 04 |shl ebp, 4

  004160D5 |. 03CD |add ecx, ebp

  004160D7 |. 8B6E 08 |mov ebp, [esi+8]

  004160DA |. 33EB |xor ebp, ebx

  004160DC |. 03CD |add ecx, ebp

  004160DE |. 8BEB |mov ebp, ebx

  004160E0 |. C1ED 05 |shr ebp, 5

  004160E3 |. 33E8 |xor ebp, eax

  004160E5 |. 03CD |add ecx, ebp

  004160E7 |. 034E 0C |add ecx, [esi+C]

  004160EA |. 66:4F |dec di

  004160EC |.^ 75 C7 jnz short 004160B5 ;------------>加密循环

  004160EE |. 5F pop edi

  004160EF |. 891F mov [edi], ebx

  004160F1 |. 894F 04 mov [edi+4], ecx

  想解出密码,我们得把密文解密 20H 次,如果直接用汇编代码逆运算是算不出来的,引用 《C 语言程序设计》中的

  一句话 "超出人的大脑能直接思考的范围 ",而且碰到 shr 之类的语句就郁闷了,因为你无法知道前一个值是什么.

  记得《C 语言程序设计》 有提到过用伪代码描述算法,我们不妨把汇编算法用 C 伪代码描述.

  密码算法 C 伪代码:

  a = 密码的前4个字节

  b = 密码的后4个字节

  n = 20H

  k = 9E3779B9H

  -------------------

  c = b << 4

  a = a + c

  c = b ^ "NJYZ"

  a = a + c

  c = b >> 5 =============================> 密码的前4个字节加密

  c = c ^ (k * n)

  a = a + c

  a = a + "-RG-"

  --------------------

  -----------------------------------------------------------------------------

  --------------------

  c = a << 4

  b = b + c

  c = a ^ "60-T"

  b = b +c

  c = a >> 5 =================================> 密码的后4个字节加密

  c = c ^ (k * n)

  b = b + c

  b = b + "T-60"

  ---------------------

  循环加密 20H 次

  经过上面的分析,大家应该对还原精灵的加密算法比较熟悉了吧!

  接下来讨论一下解密器的制作:

  可以看出前后4个字节的加密算法一样的,我们可以遍一个解密子程序

  先解出密码的后4个字节,再解出密码的前4个字节,如此循环20H次.

  下面是我自己写的还原密码破解程序的源代码,在 VC++ 6.0 下编译通过(控制台程序)

  #include "windows.h"

  #include "stdio.h"

  unsigned long esi0 = 0x5a594a4e; // "NJYZ"

  unsigned long esi4 = 0x2d47522d; // "-RG-"

  unsigned long esi8 = 0x542d3036; // "60-T"

  unsigned long esic = 0x30362d54; // "T-60"

  unsigned long edx0 = 0x9e3779b9;

  //加密常量要仔细填,不然不但算不出密码,而且也很难找出错误.

  void sub(unsigned long *a, unsigned long *b, unsigned long *a1, unsigned long

  *b1, unsigned long c1);

  void main()

  {

  printf("nttt 还原精灵 6.0 密码读取程序 nnn");

  printf("ttttt by FIGO nnn");

  printf("ttt 仅供学习交流使用,请勿用于非法目的nnnn");

  long hmov = 0;

  unsigned long *pwd;

  char str1[20];

  char *p1;

  unsigned long *p2;

  pwd = (unsigned long*)str1;

  unsigned long tmp1, tmp2, tmp3, i;

  HANDLE hFile;

  hFile = CreateFile(".PhysicalDrive0", GENERIC_ALL, FILE_SHARE_READ |

  FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

  PBYTE pBuffer = (PBYTE)malloc(512);

  DWORD dwLen;

  hmov = SetFilePointer(hFile, 0x00000e00, (long*)(&hmov), FILE_BEGIN);

  ReadFile(hFile, pBuffer, 512, &dwLen, NULL);

  p1 = (char*)pBuffer + 0x4f;

  p2 = (unsigned long*)p1;

  tmp1 = *p2;

  p2++;

  tmp2 = *p2;

  for (i = 0x20; i >= 1; i--)

  {

  tmp3 = i * edx0;

  sub(&tmp2, &tmp1, &esi8, &esic, tmp3);

  sub(&tmp1, &tmp2, &esi0, &esi4, tmp3);

  }

  *pwd = tmp1;

  pwd = pwd++;

  *pwd = tmp2;

  pwd++;

  *pwd = 0;

  printf("ttt password is : %s nnnnnnnnnnnnnn ", str1);

  CloseHandle(hFile);

  free(pBuffer);

  }

  void sub(unsigned long *a, unsigned long *b, unsigned long *a1,

  unsigned long *b1, unsigned long c1)

  {

  unsigned long higt, low, esi1, esi2, ebp0, edx1;

  edx1 = c1;

  higt = *a;

  low = *b;

  esi1 = *a1;

  esi2 = *b1;

  ebp0 = low << 4;

  higt = higt - ebp0;

  ebp0 = low ^ esi1;

  higt = higt - ebp0;

  ebp0 = low >> 5;

  ebp0 = ebp0 ^ edx1;

  higt = higt - ebp0;

  higt = higt - esi2;

  *a = higt;

  }

  至于还原精灵6.0 以上版本及还原精灵网络版6.x的算法也是一样(至少目前为止),

  只是加密的字符串不一样.

  例如:

  解还原精灵网络版 6.02(目前应该算是最新版吧)的密码,只要将上面的代码中的

  字符串 "NJYZ-RG-60-TT-60" 替换为 "NJZY-NetCard-V60" 即可.

  实际上解还原精灵6.0密码可以直接用内存注册机来解,在 0041616C 出中断,

  EAX 指向密码地址(一定要先结束掉还原精灵的进程),网络版的无此BUG.

  还原精灵各个版本一般都是把密码的明文或密文写在 0 磁道 8 扇区

  偏移量为 04FH,该扇区并没有什么特殊保护,可以直接用 CreateFile 进行读写.

(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜