Swf2MP3(国外)保护技术深入剖析
软件类别:国外软件/共享版/音频工具
运行环境:Win9x/Me/NT/2000/XP
开 发 商:http://www.hootech.com/
软件介绍:
flash工具,可以释放出flash电影中(swf 文件)所有的声音元素,同时支持突发声音和流声音,支持2种格式(.mp3和.wav).
前言:My wife要大量地从swf中取Mp3放手机里听(比如新xx的课程),网上正好有这个工具。但无注册码可找,甚感疑惑。况且这个是老外的工具,遂破之。本文主要阐述原理,细节省略。
简单流程:运行后读取注册表中一串60字节的关键数据进行处理,如果符合注册条件就正常使用,不再修改注册表数据否则会将已使用的次数加密后写入该注册表数据的特定地方,同时写入的还有判断是否注册的条件数据,最后弹出注册框显示使用的次数。该软件爆破很简单,改变一下运行的流程,就会在注册表中生成符合注册条件的数据,以后就可以正常使用了。由于卸载时不清除注册表中该处关键数据,导致在该机重装该软件后仍可正常使用。
一、先来看看如何判断是否注册。关键位置在这:
0040DE6E . 52 PUSH EDX ;三个外部参数
0040DE6F . 6A 1E PUSH 1E ;
0040DE71 . 50 PUSH EAX ;
0040DE72 . E8 C9EEFFFF CALL Swf2MP3(.0040CD40 ;//判断注册 并计算使用次数
0040DE77 . 83C4 0C ADD ESP,0C ; 返回eax=1表示注册
0040DE7A . 85C0 TEST EAX,EAX
0040DE7C . 74 1E JE SHORT Swf2MP3(.0040DE9C
0040DE7E . 8B86 8C260000 MOV EAX,DWORD PTR DS:[ESI+268C]
0040DE84 . 8BCE MOV ECX,ESI
0040DE86 . 0D 00000096 OR EAX,96000000
0040DE8B . 8986 8C260000 MOV DWORD PTR DS:[ESI+268C],EAX
; esi+268c 处存放初始值96000000
0040DE91 . E8 6A270000 CALL Swf2MP3(.00410600
0040DE96 . 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
0040DE9A . EB 13 JMP SHORT Swf2MP3(.0040DEAF
0040DE9C > 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C] ; 未注册的跳到这
0040DEA0 . 83F8 1E CMP EAX,1E ; 有没有30次
0040DEA3 . 72 0A JB SHORT Swf2MP3(.0040DEAF
0040DEA5 . 818E 8C260000>OR DWORD PTR DS:[ESI+268C],40000000
; 超过试用次数第30位置1
0040DEAF > 8B8E 8C260000 MOV ECX,DWORD PTR DS:[ESI+268C]
0040DEB5 . F7C1 00000002 TEST ECX,2000000 判断32位的标志中有无变化
0040DEBB . 74 18 JE SHORT Swf2MP3(.0040DED5
0040DEBD . F7C1 00000004 TEST ECX,4000000
0040DEC3 . 74 10 JE SHORT Swf2MP3(.0040DED5
0040DEC5 . F7C1 00000010 TEST ECX,10000000
0040DECB . 74 08 JE SHORT Swf2MP3(.0040DED5
0040DECD . F7C1 00000080 TEST ECX,80000000
0040DED3 . 75 37 JNZ SHORT Swf2MP3(.0040DF0C ; 即注册过的跳走返回1
0040DED5 > 40 INC EAX ; 上次使用的次数inc了一下
0040DED6 . 8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20]
0040DEDA . 50 PUSH EAX ;//使用的次数(含本次)
0040DEDB . 51 PUSH ECX
0040DEDC . 894424 14 MOV DWORD PTR SS:[ESP+14],EAX
0040DEE0 . E8 0BEDFFFF CALL Swf2MP3(.0040CBF0 ;生成注册表60字节数据 0040DEE5 . 83C4 08 ADD ESP,8
0040DEE8 . 8D5424 20 LEA EDX,DWORD PTR SS:[ESP+20]
0040DEEC . 8BCE MOV ECX,ESI
0040DEEE . 52 PUSH EDX
0040DEEF . 6A 01 PUSH 1
0040DEF1 . E8 4A010000 CALL Swf2MP3(.0040E040
0040DEF6 . 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
;前面调用返回的使用次数
0040DEFA . 8B4E 1C MOV ECX,DWORD PTR DS:[ESI+1C]
0040DEFD . 6A 00 PUSH 0 ; /lParam = 0
0040DEFF . 50 PUSH EAX //发送使用的次数 显示时用到
0040DF00 . 68 77040000 PUSH 477 ; |Message = MSG(477)
0040DF05 . 51 PUSH ECX ; |hWnd
0040DF06 . FF15 ACD44500 CALL DWORD PTR DS:[<&USER32.PostMessageA 0040DF0C > 5F POP EDI
0040DF0D . 5E POP ESI
0040DF0E . B8 01000000 MOV EAX,1
0040DF13 . 5B POP EBX
0040DF14 . 83C4 50 ADD ESP,50
0040DF17 . C3 RETN
0040CD40 /$ 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+4]
.......
0040CE7D |. 33C0 XOR EAX,EAX
0040CE7F |. 5B POP EBX
0040CE80 \. C3 RETN
由于算法比较复杂,用hexrays转换成伪c代码分析。
外部参数a1指向读取的注册表数据的起始处,a2是1Eh即30,a3地址处存放计算得到的已使用的次数(不包括本次)。
signed int __cdecl sub_40CD40(int a1, int a2, int a3)
{ //内部变量定义省略
....
v4 = a1;
v3 = *(_DWORD *)(a1 + 12);
if ( (v3 ^ *(_DWORD *)(a1 + 56) ^ 0xB927102E) != 698926849
|| (v5 = *(_DWORD *)(a1 + 4), v6 = *(_DWORD *)a1, a1 = *(_DWORD *)(a1 + 8), v7 = *(_DWORD *)(v4 + 16),
(v3 ^ 0xB927102E) + (v7 ^ 0xB927102E) + (a1 ^ 0xB927102E) + (v5 ^ 0xB927102E) + (v6 ^ 0xB927102E) != ~*
(_DWORD *)(v4 + 24))
|| (v8 = *(_DWORD *)(v4 + 36), (v8 ^ 0x28A79C95) * (*(_DWORD *)(v4 + 32) ^ 0x28A79C95) != ~*(_DWORD *)(v4
+ 48)) )
{
*(_DWORD *)a3 = a2 + 1;
result = 0;
}
else
{
v9 = v7 ^ *(_DWORD *)(v4 + 20) ^ 0xB927102E;
if ( v9 != -1875289631 //即0x903959E1
|| (v6 ^ *(_DWORD *)(v4 + 28) ^ 0xB927102E) != 1686250269
|| (v5 ^ *(_DWORD *)(v4 + 40) ^ 0xB927102E) != -1988021778
|| (v8 ^ *(_DWORD *)(v4 + 44) ^ 0x28A79C95) != -1740411931
|| (*(_DWORD *)(v4 + 32) ^ *(_DWORD *)(v4 + 52) ^ 0x28A79C95) != 374450403 )
{
if ( v9 == -1989516033 )
{ //未注册过的到这 此时a1是*(_DWORD *)(a1 + 8) 注意前面有重新赋值
//已使用的次数(不含本次)=偏移8处的^偏移40处的异^0xB927102E
*(_DWORD *)a3 = a1 ^ *(_DWORD *)(v4 + 40) ^ 0xB927102E;
result = 0;
}
else
{
*(_DWORD *)a3 = a2 + 1; //31次
result = 0;
}
}
else
{ //注册过的到这执行
result = 1;
}
}
return result;
}
//生成60字节注册表数据 a2是已使用的次数(含本次) a1指向60字节的数据buffer起始地址
signed int __cdecl sub_40CBF0(int a1, int a2)
{ //内部变量定义省略
....
v3 = time(0);
v4 = GetTickCount();
srand(v4 * v3);
v5 = rand();
v6 = a1;
*(_DWORD *)a1 = rand() * v5;
v7 = rand();
*(_DWORD *)(v6 + 4) = rand() * v7;
v8 = rand();
*(_DWORD *)(v6 + 8) = rand() * v8; // 偏移8h处=rand1
v9 = rand();
*(_DWORD *)(v6 + 12) = rand() * v9;
v10 = rand();
v11 = rand() * v10;
v12 = *(_DWORD *)v6 + *(_DWORD *)(v6 + 12) + *(_DWORD *)(v6 + 8);
*(_DWORD *)(v6 + 16) = v11;
*(_DWORD *)(v6 + 24) = ~(*(_DWORD *)(v6 + 4) + v11 + v12);
v13 = rand();
*(_DWORD *)(v6 + 32) = rand() * v13;
v14 = rand();
v15 = rand() * v14;
*(_DWORD *)(v6 + 36) = v15;
v16 = *(_DWORD *)(v6 + 12) ^ 0x29A8C701;
v17 = *(_DWORD *)(v6 + 16) ^ 0x896A64FF;
*(_DWORD *)(v6 + 48) = ~(*(_DWORD *)(v6 + 32) * v15);
*(_DWORD *)(v6 + 56) = v16;
*(_DWORD *)(v6 + 20) = v17;
v18 = rand();
v19 = a2; //注意v19变成了已使用的次数(含本次)
*(_DWORD *)(v6 + 28) = v18;
*(_DWORD *)(v6 + 40) = v19 ^ *(_DWORD *)(v6 + 8); // 偏移40处=已使用的次数(含本次)^rand1
*(_DWORD *)(v6 + 44) = rand();
v20 = rand();
v21 = *(_DWORD *)v6;
v22 = *(_DWORD *)(v6 + 4);
*(_DWORD *)(v6 + 52) = v20;
*(_DWORD *)v6 = v21 ^ 0xB927102E;
v23 = *(_DWORD *)(v6 + 12);
v24 = *(_DWORD *)(v6 + 8) ^ 0xB927102E; //v24=rand1^ 0xB927102E
*(_DWORD *)(v6 + 4) = v22 ^ 0xB927102E;
v25 = *(_DWORD *)(v6 + 16);
*(_DWORD *)(v6 + 8) = v24; //偏移8处的=rand1^ 0xB927102E
v26 = *(_DWORD *)(v6 + 32);
*(_DWORD *)(v6 + 12) = v23 ^ 0xB927102E;
v27 = *(_DWORD *)(v6 + 36);
*(_DWORD *)(v6 + 16) = v25 ^ 0xB927102E;
*(_DWORD *)(v6 + 32) = v26 ^ 0x28A79C95;
*(_DWORD *)(v6 + 36) = v27 ^ 0x28A79C95;
return 1;
}
到此根据第一个伪代码中的:已使用的次数(不含本次)=偏移8处的^偏移40处的^0xB927102E
下次程序运行时CALL Swf2MP3(.0040CD40 调用中将计算得到:
运行计数=rand1^ 0xB927102E^已使用的次数^rand1^0xB927102E=已使用的次数
二、再来看看注册算法。位置在这:
0040CE90 /$ 83EC 60 SUB ESP,60
0040CE93 |. 56 PUSH ESI
0040CE94 |. 8B7424 68 MOV ESI,DWORD PTR SS:[ESP+68]
0040CE98 |. 56 PUSH ESI ; /String
0040CE99 |. FF15 F0D24500 CALL DWORD PTR DS:[<&KERNEL32.lstrlenA>] ; \lstrlenA
0040CE9F |. 83F8 40 CMP EAX,40
0040CEA2 |. 74 07 JE SHORT 111.0040CEAB
0040CEA4 |. 33C0 XOR EAX,EAX
0040CEA6 |. 5E POP ESI
0040CEA7 |. 83C4 60 ADD ESP,60
0040CEAA |. C3 RETN
0040CEAB |> 53 PUSH EBX
0040CEAC |. 55 PUSH EBP
0040CEAD |. 8B2D A0D24500 MOV EBP,DWORD PTR DS:[<&KERNEL32.lstrcpy>; kernel32.lstrcpynA
0040CEB3 |. 57 PUSH EDI
0040CEB4 |. 8D7C24 10 LEA EDI,DWORD PTR SS:[ESP+10]
0040CEB8 |. BB 08000000 MOV EBX,8
0040CEBD |> 6A 09 /PUSH 9
0040CEBF |. 8D4424 34 |LEA EAX,DWORD PTR SS:[ESP+34]
0040CEC3 |. 56 |PUSH ESI
0040CEC4 |. 50 |PUSH EAX
0040CEC5 |. FFD5 |CALL EBP
0040CEC7 |. 57 |PUSH EDI
0040CEC8 |. 8D4C24 34 |LEA ECX,DWORD PTR SS:[ESP+34]
0040CECC |. 68 08354700 |PUSH 111.00473508 ; ASCII "%X"
0040CED1 |. 51 |PUSH ECX
0040CED2 |. 83C6 08 |ADD ESI,8
0040CED5 |. E8 59DD0200 |CALL 111.0043AC33
0040CEDA |. 83C4 0C |ADD ESP,0C
0040CEDD |. 83C7 04 |ADD EDI,4
0040CEE0 |. 4B |DEC EBX
0040CEE1 |.^ 75 DA \JNZ SHORT 111.0040CEBD
0040CEE3 |. 8B4C24 2C MOV ECX,DWORD PTR SS:[ESP+2C]
0040CEE7 |. 8B5424 14 MOV EDX,DWORD PTR SS:[ESP+14]
0040CEEB |. 8BC1 MOV EAX,ECX
0040CEED |. 8B7C24 1C MOV EDI,DWORD PTR SS:[ESP+1C]
0040CEF1 |. 33C2 XOR EAX,EDX
0040CEF3 |. 8B7424 20 MOV ESI,DWORD PTR SS:[ESP+20]
0040CEF7 |. 25 4AC59854 AND EAX,5498C54A
0040CEFC |. 8B5C24 10 MOV EBX,DWORD PTR SS:[ESP+10]
0040CF00 |. 8BD0 MOV EDX,EAX
0040CF02 |. 334424 14 XOR EAX,DWORD PTR SS:[ESP+14]
0040CF06 |. 33D1 XOR EDX,ECX
0040CF08 |. 895424 38 MOV DWORD PTR SS:[ESP+38],EDX
0040CF0C |. 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28]
0040CF10 |. 8BCA MOV ECX,EDX
0040CF12 |. 894424 40 MOV DWORD PTR SS:[ESP+40],EAX
0040CF16 |. 33CF XOR ECX,EDI
0040CF18 |. 8B4424 18 MOV EAX,DWORD PTR SS:[ESP+18]
0040CF1C |. 81E1 74ECAB79 AND ECX,79ABEC74
0040CF22 |. 8BF9 MOV EDI,ECX
0040CF24 |. 33FA XOR EDI,EDX
0040CF26 |. 8B5424 18 MOV EDX,DWORD PTR SS:[ESP+18]
0040CF2A |. 33D6 XOR EDX,ESI
0040CF2C |. 81F7 651A4398 XOR EDI,98431A65
0040CF32 |. 81E2 B759B15A AND EDX,5AB159B7
0040CF38 |. 8BEA MOV EBP,EDX
0040CF3A |. 33D0 XOR EDX,EAX
0040CF3C |. 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C]
0040CF40 |. 33EE XOR EBP,ESI
0040CF42 |. 8B7424 24 MOV ESI,DWORD PTR SS:[ESP+24]
0040CF46 |. 895424 4C MOV DWORD PTR SS:[ESP+4C],EDX
0040CF4A |. 8B5424 24 MOV EDX,DWORD PTR SS:[ESP+24]
0040CF4E |. 33F3 XOR ESI,EBX
0040CF50 |. 81E6 3C658A64 AND ESI,648A653C
0040CF56 |. 33C8 XOR ECX,EAX
0040CF58 |. 8B4424 38 MOV EAX,DWORD PTR SS:[ESP+38]
0040CF5C |. 8BDE MOV EBX,ESI
0040CF5E |. 335C24 10 XOR EBX,DWORD PTR SS:[ESP+10]
0040CF62 |. 33F2 XOR ESI,EDX
0040CF64 |. 8BD7 MOV EDX,EDI
0040CF66 |. 81F5 E4651A32 XOR EBP,321A65E4
0040CF6C |. 33D0 XOR EDX,EAX
0040CF6E |. 81F3 436584CA XOR EBX,CA846543
0040CF74 |. 81FA 54C64865 CMP EDX,6548C654
0040CF7A |. 75 6C JNZ SHORT 111.0040CFE8
0040CF7C |. 33F5 XOR ESI,EBP
0040CF7E |. 81FE 6248C5A8 CMP ESI,A8C54862
0040CF84 |. 75 62 JNZ SHORT 111.0040CFE8
0040CF86 |. 33CF XOR ECX,EDI
0040CF88 |. 81F9 EFA36821 CMP ECX,2168A3EF
0040CF8E |. 75 58 JNZ SHORT 111.0040CFE8
0040CF90 |. B8 F1F0F0F0 MOV EAX,F0F0F0F1
0040CF95 |. F7E3 MUL EBX
0040CF97 |. C1EA 04 SHR EDX,4
0040CF9A |. B8 4FECC44E MOV EAX,4EC4EC4F
0040CF9F |. 8BCA MOV ECX,EDX
0040CFA1 |. F7E3 MUL EBX
0040CFA3 |. 0FAFCD IMUL ECX,EBP
0040CFA6 |. C1EA 02 SHR EDX,2
0040CFA9 |. 0FAFD7 IMUL EDX,EDI
0040CFAC |. 03CA ADD ECX,EDX
0040CFAE |. 8BD5 MOV EDX,EBP
0040CFB0 |. 0FAFD7 IMUL EDX,EDI
0040CFB3 |. 8B4424 40 MOV EAX,DWORD PTR SS:[ESP+40]
0040CFB7 |. 03CA ADD ECX,EDX
0040CFB9 |. F7D1 NOT ECX
0040CFBB |. 3BC8 CMP ECX,EAX
0040CFBD |. 75 29 JNZ SHORT 111.0040CFE8
0040CFBF |. 8BCB MOV ECX,EBX
0040CFC1 |. B8 ABAAAAAA MOV EAX,AAAAAAAB
0040CFC6 |. 0FAFCF IMUL ECX,EDI
0040CFC9 |. F7E1 MUL ECX
0040CFCB |. 8B4424 4C MOV EAX,DWORD PTR SS:[ESP+4C]
0040CFCF |. D1EA SHR EDX,1
0040CFD1 |. 2BDA SUB EBX,EDX
0040CFD3 |. 03DD ADD EBX,EBP
0040CFD5 |. F7D3 NOT EBX
0040CFD7 |. 3BD8 CMP EBX,EAX
0040CFD9 |. 75 0D JNZ SHORT 111.0040CFE8
0040CFDB |. 5F POP EDI
0040CFDC |. 5D POP EBP
0040CFDD |. 5B POP EBX
0040CFDE |. B8 01000000 MOV EAX,1
0040CFE3 |. 5E POP ESI
0040CFE4 |. 83C4 60 ADD ESP,60
0040CFE7 |. C3 RETN
0040CFE8 |> 5F POP EDI
0040CFE9 |. 5D POP EBP
0040CFEA |. 5B POP EBX
0040CFEB |. 33C0 XOR EAX,EAX
0040CFED |. 5E POP ESI
0040CFEE |. 83C4 60 ADD ESP,60
0040CFF1 \. C3 RETN
由于算法很变态,没有耐心是看不完的。伪代码如下:
//lpString2是你输入的注册码
bool __cdecl sub_40CE90(LPCSTR lpString2)
{ const CHAR *v1; // esi@1
bool result; // eax@2
signed int v3; // ebx@3
int *v4; // edi@3
int v5; // ecx@5
int v6; // ebx@5
int v7; // ebp@5
int v8; // edi@5
int v9; // ecx@5
int v10; // [sp+4h] [bp-60h]@3
CHAR Src; // [sp+24h] [bp-40h]@4
int v12; // [sp+8h] [bp-5Ch]@5
int v13; // [sp+20h] [bp-44h]@5
int v14; // [sp+34h] [bp-30h]@5
int v15; // [sp+10h] [bp-54h]@5
int v16; // [sp+1Ch] [bp-48h]@5
int v17; // [sp+Ch] [bp-58h]@5
int v18; // [sp+14h] [bp-50h]@5
int v19; // [sp+40h] [bp-24h]@5
int v20; // [sp+18h] [bp-4Ch]@5
v1 = lpString2;
if ( lstrlenA(lpString2) == 64 )//长度必须64位
{
v4 = &v10;
v3 = 8;
do
{
lstrcpynA(&Src, v1, 9);
v1 += 8;
sscanf(&Src, "%X", v4);
++v4;
--v3; //循环8次分成8组
}
while ( v3 );
v14 = v12 ^ (v12 ^ v13) & 0x5498C54A;
v9 = (v15 ^ v16) & 0x79ABEC74;
v8 = v16 ^ v9 ^ 0x98431A65;
v19 = v17 ^ (v18 ^ v17) & 0x5AB159B7;
v5 = v15 ^ v9;
v7 = v18 ^ (v18 ^ v17) & 0x5AB159B7 ^ 0x321A65E4;
v6 = v10 ^ (v10 ^ v20) & 0x648A653C ^ 0xCA846543;
result = (v13 ^ (v12 ^ v13) & 0x5498C54A ^ v8) == 1699268180
&& (v7 ^ v20 ^ (v10 ^ v20) & 0x648A653C) == -1463465886
&& (v8 ^ v5) == 560505839
&& ~(v8 * v7 + v8 * v6 / 0xDu + v7 * v6 / 0x11u) == v14
&& ~(v7 + v6 - v8 * v6 / 3u) == v19;
} //必须5个条件同时为真
else
{
result = 0;
}
return result; //1 表示注册成功
}
简单的说将你输入的注册码转换成8个变量,这8个变量互相组合又多出7个变量,然后这15个变量要同时满足5个等式,这样注册才会成功。用伪c代码看成这样,那么直接看汇编你能看懂那你就可以当坛主了。这也是网上找不到注册码的原因。当然你可以直接爆破,这是没有办法的办法。
天易love
2009.2.5
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)