能力值:
( LV12,RANK:345 )
2 楼
Sorry,原来上传附件后图片自动显示!
能力值:
( LV9,RANK:140 )
3 楼
这个月一直很忙没多少时间看论坛帖子,简单看了一下这个CM,
整个解密算法的流程应该是这样吧:
读取“Windows.iso”文件,(Windows.iso是一个PE模块,并且每位字节都经过加密处理过)
解密的过程:
00401161 |> /8A06 /MOV AL,BYTE PTR DS:[ESI] ; 依次读取注册码每字节
00401163 |. |8A1F |MOV BL,BYTE PTR DS:[EDI] ; 依次读取每字节密钥
00401165 |. |D0EB |SHR BL,1 ; 每位密钥除2
00401167 |. |02C3 |ADD AL,BL ; 输入的注册码每字节加上面的除2的结果
00401169 |. |8807 |MOV BYTE PTR DS:[EDI],AL ; 密钥的第一个字节改变
0040116B |. |46 |INC ESI ; 读取的注册码字串地址自增
0040116C |. |47 |INC EDI ; 密钥地址自增
0040116D |.^\E2 F2 \LOOPD SHORT CM_One.00401161
解密有个密钥,密钥是是由注册用户名来计算得到了,长度跟密钥长度一样,
0040107A |. F6F3 DIV BL ; 用户名ascii第一字节 除以 (第二字节+1)
0040107C |. 66:0FB6C4 MOVZX AX,AH ; 取余数
00401080 |. 8A5E 02 MOV BL,BYTE PTR DS:[ESI+2] ; 第三个字节放到bl
.................
..................
然后反复循环那个密钥对文件Windows.iso每个字节解密,
第一次正常循环这个密钥依次,
第二次以后,
00401201 |. 803F 00 |CMP BYTE PTR DS:[EDI],0
00401204 |. 75 06 |JNZ SHORT CM_One.0040120C
00401206 |. 8D3D 1E304000 |LEA EDI,DWORD PTR DS:[40301E] ; 从第二次开始
0040120C |> 8A06 |MOV AL,BYTE PTR DS:[ESI]
0040120E |. 3207 |XOR AL,BYTE PTR DS:[EDI]
00401210 |. A2 18304000 |MOV BYTE PTR DS:[403018],AL
00401215 |. 47 |INC EDI
除了密钥第一个字节改变外,其它不变,反复循环密钥(第二次以后密钥改变)对文件每字节解密,
并依次写入文件“WinXP.iso”每字节,
完成后调用LoadLibraryA 加载模块并 DeleteFileA删除文件
..................
不知道分析得对不对,马马虎虎.
能力值:
( LV15,RANK:440 )
4 楼
LS 反应如此之快
有空玩,哎。
能力值:
( LV12,RANK:345 )
5 楼
第一次正常循环这个密钥依次,
第二次以后,
00401201 |. 803F 00 |CMP BYTE PTR DS:[EDI],0
00401204 |. 75 06 |JNZ SHORT CM_One.0040120C
00401206 |. 8D3D 1E304000 |LEA EDI,DWORD PTR DS:[40301E] ; 从第二次开始
0040120C |> 8A06 |MOV AL,BYTE PTR DS:[ESI]
0040120E |. 3207 |XOR AL,BYTE PTR DS:[EDI]
00401210 |. A2 18304000 |MOV BYTE PTR DS:[403018],AL
00401215 |. 47 |INC EDI
除了密钥第一个字节改变外,其它不变,反复循环密钥(第二次以后密钥改变)对文件每字节解密,
兄才果然神速,总体的思路正确解密.ISO,生成新的.ISO文件并加载,不过请注意下上面解密过程中使用的是同一个密钥第二次并没有改变密钥!还有密钥是由用户名和密码共同算出来的,且密钥长度为……,
关键是解密过程,请大家加油,搞出一组用户名和密码,瞧见MSG窗体!
能力值:
( LV9,RANK:140 )
6 楼
刚下课回来,外面下大雨了,落汤鸡了.....
密钥在内存中是没变化,但是,第二次开始计算的时候它不按照密钥的第一个字节计算,
长度跟用户名长度是一样的,应该不会错
要考试了,我的时间比较紧,密钥的生成过程我没去彻底分析,有空的朋友可以分析一下,算法应该不是很复杂的。
能力值:
( LV15,RANK:440 )
7 楼
username:lovemm
password:齆?pU
password二进制形式为:FD 4E EB 1C 70 A4 63 55
得在二进制编辑器里粘一下。
密码长度应该是8,貌似不是所有合法的用户名均可以生成正常key,求LZ点评................
上传的附件:
能力值:
( LV12,RANK:345 )
8 楼
username:lovemm
的密码确实为password二进制形式为:FD 4E EB 1C 70 A4 63 55
兄才果然神速,此CM并非针对每一个用户名,都有对应的可现实字符。需要特定的可显示用户名和密钥才能生成最终解密密钥,来解密文档。因为解密密钥是固定的。我想说兄才,是否是逆推的呢~
能力值:
( LV15,RANK:440 )
9 楼
嗯,是逆推的。用PE文件的特征可以分析出那个8个字节的解密密钥来。然后用你的第一个函数作为注册机的第一个部分。
能力值:
( LV3,RANK:20 )
10 楼
猀c礋..
winndowsa
二进制编辑器粘才可以
复制粘贴错了
能力值:
( LV12,RANK:345 )
11 楼
嗯,其实掌握PE的基本知识这个CM就没什么难度可言了。
还有我请教下"hackerlzc"兄,对于riijj的CM2可曾有什么见解指出,提供下思路。
大家,如果有曾分析的也可以讨论下思路,很纠结~至今没有被破
能力值:
( LV15,RANK:440 )
12 楼
好像没见过那个东西呢,给个下载连接吧,有空研究下。
能力值:
( LV12,RANK:345 )
13 楼
能力值:
( LV13,RANK:410 )
14 楼
注册码生成算法:
BYTE un[0x10]={0};
BYTE key2[0x10]={0};
BYTE sn[0x10]={0x4C,0x91,0x5D,0x56,0x8B,0xA9,0x63,0x55,0x4C,0x91,0x5D,0x56,0x8B,0xA9,0x63,0x55};
BYTE fixedKey[]={0x4C,0x91,0x5D,0x56,0x8B,0xA9,0x63,0x55,0x4C,0x91,0x5D,0x56,0x8B,0xA9,0x63,0x55};
DWORD temp1=(DWORD)(0-1)/(((un[0]%un[1])*un[2])+1);
for (int i=0;i<0x0f;i++)
{
temp1=temp1*0x342ab+0x269ec3;
}
for (unsigned int i=0;i<strlen((PCHAR)un);i++)
{
signed short int a=(un[i]>>5)*0x7b;
while(a>0)
{
temp1=temp1*0x123cd+0x775851;
a--;
}
temp1=temp1*0x123cd+0x269ec3;
key2[i]=(BYTE)(temp1>>0x10);
sn[i]=fixedKey[i]-key2[i]/2;
sn[8]=-(key2[8]/2);
}
能力值:
( LV9,RANK:180 )
15 楼
现在被破了
上传的附件:
能力值:
( LV15,RANK:440 )
16 楼
S大,。。。。。。。现身了……
能力值:
( LV12,RANK:345 )
17 楼
S大,求解释!有时间的话出个思路吧
能力值:
( LV9,RANK:180 )
18 楼
riijj的CM2看似乱, 其实有个弱点
找出弱点是这个CM好玩的地方, 所以讲出来就没意思了
你仔细思考思考一定行的
能力值:
( LV12,RANK:345 )
19 楼
多谢提醒,继续看
能力值:
( LV15,RANK:440 )
20 楼
附件是注册机。
上传的附件:
能力值:
( LV12,RANK:345 )
21 楼
大S,低16位数据看出来了,不过高16位数据没看出来规律……
能力值:
( LV9,RANK:180 )
22 楼
有些天了...凭印象花了时间写下下面东西, 有错误的话请自己抓Bug
file_r2.iot 是一支被加密的 dll
这是 file_r2.iot 前面的内容, 总大小为A000h
00~0F: 5E BB EF E9 2E 36 EE BF 2E BB EF A3 D1 4B FF 56
10~1F: 91 52 19 6B 5B 7B E3 B9 6A A3 64 73 0A FF EF DB
20~2F: 74 D5 EF BF 2E BB EF BF 2E BB EF BF 2E BB EF BF
30~3F: 2E BB EF BF 2E BB EF 55 5C BB EF BF 2E BB EF A8
40~4F: 2E BB D4 EF 32 41 9B 9B 69 D4 9B BF 2E BB EF BF
一个正确的 Key 可将这东西解成文件名为 ffe10.iot 的 dll
这是常见的标准 dll 前 16 byte :
00~0F: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00
Name 及 SN => 经过 0040125A xor ebp, esi 后的值称为 Key
Key 的 HiWord 会决定出一张位置表, 所以理论上有 65536 种位置表
Key 的 LoWord 会被拆成 4 个 Byte, 用来做为 xor 用, 如下:
X0: 00xxxxxxxx000000
X1: 0000xxxxxxxx0000
X2: 000000xxxxxxxx00
X3: 00000000xxxxxxxx
所以实际上只用到 14 个 bit
004012E2 到 0040132F 这个回圈会设好位置表
回圈里的 00401319 mov [edx+eax*4], ebp
这条指令 ebp 会由 0 跑 到 9FFF
eax 则是变动的
这张表是什么意思呢 ? 假设有一 HiWord 导致:
当 ebp=0 时, eax=1111h , 表示 file_r2[1111h] 将是 dll 的第 0 个 byte
当 ebp=1 时, eax=2222h , 表示 file_r2[2222h] 将是 dll 的第 1 个 byte
以此类推...
[程序的解码行为]
1. ffe10.iot 里的内容由 0~9FFF 依序分别跟 X0,X1,X2,X3(循环) 做 XOR 运算
这张新的表我们暂时称为 DTable
2. 根据位置表来移动 Byte, 以我上面举的例子:
DTable[[1111h] 将成为 dll 的 byte 0 , 正确的话是 4A
DTable[[2222h] 将成为 dll 的 byte 1 , 正确的话是 5D
由于 HiWord'LoWord 全是我们自己决定的, 所以...
1. 65536 张的位置表, 我们并不知道那一张才是正确的
2. 我们也不知道 X0'X1'X2'X3 的正确值
我的解法是
那个回圈我们不须要完成整张(大小A000), 我们只需前 16 byte 即可
亦即让 00401319 mov [edx+eax*4], ebp 只执行 16 次
由 eax 的值我们已可得知前 16 个 byte 的位置 (eax本身)
由 eax 的值我们已可得知前 16 个 byte 的值 (file_r2[eax])
前16个值 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
正常 DLL : 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00
而因为位置(eax本身)我们也知道, 所以还可得知各是 xor X0还是X1还是X2还是X3
前16个值 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
正常 DLL : 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00
X : eax mod 4 (你可直接写成 and eax,3)
所以现有资讯为 :
前16个值 : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
正常 DLL : 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00
X : 01 02 00 01 02 03 03 02 00 01 00 00 03 02 00 04 <- 假设
你看当 0'3'9 , 其 X 都是 01
你看当 1'4'7'D , 其 X 都是 02
...
若是正确的位置表出现的话, 会有下列现象 :
4D ^ 前16个值[0]
= 00 ^ 前16个值[3]
= 00 ^ 前16个值[9]
5A ^ 前16个值[1]
= 03 ^ 前16个值[4]
= 00 ^ 前16个值[7]
= FF ^ 前16个值[D]
....
实际上你不用全部判断, 我当时是每张位值表只取 X[0] , 假设是 01
则找出剩下的 15 个 X 也是 01 的部份, 其上面二值 XOR 后的值若是一样的即是正确的 Table
同时, LoWord 也现形了(有可能只有1'2个bit还未知而己)
须注意的是, 你在渐增 Key 时,你不要只加 1 , 而是应该加 10000h
应该 1 秒内可以跑出来正确的 Key
另一种被作者和谐掉的穷举方法是:
一样只取前 16 byte, 同样也获得了下列资讯 :
由 eax 的值我们已可得知前 16 个 byte 的位置 (eax本身)
由 eax 的值我们已可得知前 16 个 byte 的值 (file_r2[eax])
但你 LoWord 由 0 穷举到 3FFF (14个bit) 以判断是否是 4D 5A 90 00 03 ...
花费的时间最多将是 3FFF 倍
现今的电脑并不是问题, 应该也快, 但已失去了发现漏洞的乐趣了
能力值:
( LV15,RANK:440 )
23 楼
// hello.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<string.h>
#include<stdio.h>
#include<malloc.h>
#include<windows.h>
#include<stdlib.h>
#if 1
int _tmain(int argc, _TCHAR* argv[])
{
FILE *fp1,*fp2;
unsigned int key,password,sum_name = 1,key2,*hashtable,varKey,nSize,pos[16];
int i,j,count = 0;
unsigned char *out_buffer,*table_flag,ch,*flag;
unsigned char res[16] = {0x4d,0x5a,0x90,0x00,0x03,0,0,0,0x04,0,0,0,0xff,0xff,0,0};
fp1 = fopen("file_r2.iot","rb");
fseek( fp1,0l,SEEK_END );
nSize = ftell( fp1 );
rewind( fp1 );
table_flag = (unsigned char *)calloc( nSize,1 );
flag = (unsigned char *)calloc( nSize,1 );
hashtable = (unsigned int *)calloc( 4*nSize,1 );
fread( table_flag,nSize,1,fp1 );
fclose( fp1 );
fp1 = fopen("key.txt","w");
for( key2 = 1;key2 <= 0xffff;key2++)
{
unsigned char turn[4]={0},header[16] = {0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00};
varKey = 1;
for( j = 0;j < 16;j++)
{
varKey = (varKey * 0x19913 % nSize + key2 ) % nSize;
pos[j] = varKey;
}
if( (table_flag[ pos[0] ] ^ 0x4d) != (table_flag[pos[4]] ^ 0x03))continue;
if( (table_flag[ pos[1] ] ^ 0x5a) != (table_flag[pos[5]] ^ 0x00))continue;
if( (table_flag[ pos[2] ] ^ 0x90) != (table_flag[pos[6]] ^ 0x00))continue;
if( (table_flag[ pos[3] ] ^ 0x00) != (table_flag[pos[7]] ^ 0x00))continue;
if( (table_flag[ pos[8] ] ^ 0x04) != (table_flag[pos[12]] ^ 0xff))continue;
if( (table_flag[ pos[9] ] ^ 0x00) != (table_flag[pos[13]] ^ 0xff))continue;
if( (table_flag[ pos[10] ] ^ 0x00) != (table_flag[pos[14]] ^ 0x00))continue;
if( (table_flag[ pos[11] ] ^ 0x00) != (table_flag[pos[15]] ^ 0x00))continue;
memset( flag,0,nSize );
memset( hashtable,0,4*nSize );
varKey = 1;
for( j = 0;j < nSize;j++)
{
varKey = (varKey * 0x19913 % nSize + key2 ) % nSize;
for( i = varKey;i <= nSize;i++)
{
if( i == nSize )i=0;
if( flag[i] == 0 )
{
flag[i] = 1;
hashtable[i] = j;
if( j < 16 )pos[j] = i;
break;
}
}
}
printf("\n");
for( i = 0;i < 16;i++)
turn[pos[i]%4] = (table_flag[ pos[i] ] ^ header[i]);
for( i = 0;i < 4;i++)
printf("%x ",turn[i] );
printf("\n");
//在此处找到turn不为0的元素,修改下边相应代码
//turn只有1,3项有效,可以算出低12位
turn[0] = 0; //经过进一步验证,第13-12位为00
for( j = 0;j < 4;j++)
{
key = 0;
key |= key2 << 16;
key |= j << 14;
key |= ((turn[0])&0xc0)<<6;
key |= ((turn[1])&0xf0)<< 4;
//key |= ((turn[2])&0xc0)<< 2;
key |= ((turn[3])&0xff);
if( ((key * 0x80008001ull)>>47 ) == (long long)key2 )
printf("key = %x\n",key );
else
printf("key = %x\n",key - 0x10000);
}
}
fclose(fp1);
system("PAUSE");
return 0;
}
#endif
#if 0
int _tmain(int argc, _TCHAR* argv[])
{
FILE *fp1,*fp2;
unsigned int key,password,sum_name = 1,key2,*hashtable,varKey,nSize;
int i,j;
char *out_buffer,*table_flag,ch;
char res[16] = {0x4d,0x5a,0x90,0x00,0x03,0,0,0,0x04,0,0,0,0xff,0xff,0,0};
fp1 = fopen("file_r2.iot","rb");
fseek( fp1,0l,SEEK_END );
nSize = ftell( fp1 );
rewind( fp1 );
table_flag = (char *)calloc( nSize,1 );
fread( table_flag,nSize,1,fp1 );
fclose( fp1 );
fp1 = fopen("key.txt","w");
key = 0xbf2b4bbf;
for( ;key < 0xffffffff;key++)
{
//printf("%x\n",key );
_asm
{
mov eax,80008001h
mov ecx,key
xor edx,edx
mul ecx
shr edx,0fh
mov key2,edx
}
printf("key = %x,key2 = %x\n",key,key2 );
system("PAUSE");
varKey = 1;
for( j = 0;j < 16;j++)
{
unsigned char cl,cl1;
varKey = (varKey * 0x19913 % nSize + key2 ) % nSize;
i = varKey;
cl = ((i & 3)<<1) & 0xff;
cl1 = (6 - ((i&3)<<1))&0xff;
if( res[j] != (char)((((key << cl) >> cl)>>cl1) ^ table_flag[i]))
break;
}
if( j == 16 )
{
static int k = 0;
printf("k = %d\n",k );
switch(k)
{
case 2:
case 6:
case 10:
case 14:
case 16:
case 20:
case 24:
case 28:
fprintf(fp1,"0x%x,",key );
}
k++;
}
}
printf("Completed!\n");
fclose( fp1 );
getchar();
getchar();
return 0;
}
#endif
能力值:
( LV2,RANK:10 )
24 楼
学习下,感谢分析
能力值:
( LV7,RANK:110 )
25 楼
不算太难!
上传的附件: