吾爱破解安全大赛cm6分析
程序通过创建新的线程来完成验证工作: if ( (unsigned __int16)a3 == 1001 )
{
ThreadId = 0;
CreateThread(0, 0, StartAddress, lpParameter, 0, (LPDWORD)&ThreadId);
return 0;
}
其中serial是通过变形的base64算法加密的,在base64算法4合3的过程中对每字节分别进行异或:v8 = (4 * (_BYTE)v + ((BYTE1(v) >> 4) & 3)) ^ 0x4C;
v9 = (16 * BYTE1(v) + ((BYTE2(v) >> 2) & 0xF)) ^ 0x43;
v17 = (BYTE3(v) + (BYTE2(v) << 6)) ^ 0x47;
v17 = v8;
v17 = v9;
真正的serial将由4部分组成,竞赛时提供的key 解密后的内容:{"name": "360",
"key1": "--... .---- ----- ..... ----- ....- ..--- .---- .---- ---.. ----- ....- ...-- ",
"key2": "492357816",
"key3": "11111111111111119999"
}
第一部分name应与username相同。接下来的3个key分别对应3个验证函数,只有都验证通过才算成功。
Key1是摩斯电码,解密后的值为7105042118043。以下是验证函数:char __cdecl sub_404B60(int a1, const char *a2)
{
int v2; // ecx@3
unsigned int key1_0_len; // esi@5
unsigned int v4; // ebx@6
unsigned int key1_v0; // edi@8
unsigned int key1_v1; // esi@8
unsigned __int64 v7; // rax@12
int v8; // esi@13
char key1_0_10; // @8
int v11; // @8
int v12; // @8
char v13; // @8
char key1_10_?; // @8
int v15; // @8
int v16; // @8
char v17; // @8
CHAR v18; // @13
int v19; // @13
int v20; // @13
__int16 v21; // @13
char v22; // @13
if ( a2 )
{
if ( strlen(a2) )
{
v2 = MorseDecode(a2); // 摩斯电码解密
if ( v2 > 0 )
{
if ( (unsigned int)(v0 - '5') > 2
|| (key1_0_len = v0 - '0', key1_0_len >= v2 - 1)// 第一个数字为key1_0的长度
|| (v4 = v2 - key1_0_len - 1, v4 < 5)
|| v4 > 7 )
{
free(0);
}
else
{
key1_0_10 = 0;
v11 = 0;
v12 = 0;
v13 = 0;
cutstring((int)&key1_0_10, 10, 1, key1_0_len);// 取前key1_0_Len位
key1_10_? = 0;
v15 = 0;
v16 = 0;
v17 = 0;
cutstring((int)&key1_10_?, 10, key1_0_len + 1, v4);// 取之后
free(0);
key1_v0 = atoi(&key1_0_10);
key1_v1 = atoi(&key1_10_?);
if ( key1_v0 >= 10000 )
{
if ( IsPrime(key1_v0) ) // 判断是否为素数
{
if ( key1_v1 >= 10000 )
{
if ( IsPrime(key1_v1) )
{
v7 = key1_v0 * (unsigned __int64)key1_v1;// 相乘
if ( v7 - 10000000000i64 <= 89999999999i64 )
{
v18 = 0;
v19 = 0;
v20 = 0;
v21 = 0;
v22 = 0;
wsprintfA(&v18, "%I64d", v7);// 相乘后的字符串
v8 = 0;
while ( haveChar(&v18, v8 + '0') )// 判断是否包含0-9所有数字
{
if ( (unsigned int)++v8 >= 0xA )
return 1;
}
}
}
}
}
}
}
}
}
}
return 0;
}
可以得出key1必须满足的条件有:①.第一个数字为key1_0的长度,key1_0>=10000且为素数②.key1_1>=10000且为素数③.Key1_0*key1_1在10000000000-89999999999之间,且包含0-9所有数字
写一个脚本就能获取到很多这样的数字:import math
def isPrime(n):
if n <= 1:
return False
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
return False
return True
t="0123456789"
def check(x):
s=str(x)
for a in t:
if s.find(a)==-1:
return False
return True
p=[]
for a in range(10000,200000):
if isPrime(a):
p.append(a)
print len(p)
max=40
i=0
for a in p:
for b in p:
c=a*b
if c>10000000000 and c<89999999999:
if check(c):
i=i+1
print a,b
if i==max:
exit(0)
Key2的验证就有些复杂了,以下是验证部分:char __cdecl sub_407DD0(char *username, const char *key2)
{
unsigned int v2; // esi@3
unsigned int v3; // edi@3
char v4; // dl@4
int v5; // eax@4
unsigned __int64 v6; // kr08_8@10
unsigned int v7; // eax@10
char v8; // bl@11
_BYTE *v9; // esi@11
char result; // al@14
unsigned int v11; // @3
unsigned int v12; // @3
unsigned int v13; // @3
if ( key2 && strlen(key2) == 9 )
{
v2 = 1;
v13 = 0;
v3 = 0;
v12 = 0;
v11 = 0;
do
{
v4 = key2;
v5 = -1;
if ( (unsigned __int8)(v4 - '0') > 9u )
{
if ( (unsigned __int8)(v4 - 'A') > 5u )
{
if ( (unsigned __int8)(v4 - 'a') <= 5u )
v5 = v4 - 'W';
}
else
{
v5 = v4 - '7';
}
}
else
{
v5 = v4 - '0';
}
v6 = mulx64(v5, __PAIR__(v2, v11)) + __PAIR__(v12, v13);
v12 = HIDWORD(v6);
v13 = v6;
++v3;
v7 = __PAIR__(v2, v11) >> 4;
v2 >>= 4;
v11 = v7;
}
while ( v3 < 9 );
v8 = 0;
v9 = alloc(0x20118);
*v9 = 1;
set_vm_handler((int)(v9 + 4));
*v9 = 0;
malloc(v9 + 280, 0, 0x20000);
malloc(v9 + 112, 0, 168);
*((_DWORD *)v9 + 64) = 0;
*((_DWORD *)v9 + 65) = 0;
*((_DWORD *)v9 + 66) = 1024;
*((_DWORD *)v9 + 67) = 0;
*((_DWORD *)v9 + 60) = 10;
*((_DWORD *)v9 + 61) = 0;
set_vm_data(v6, SHIDWORD(v6));
vm_dispatch(v9);
if ( *((_DWORD *)v9 + 28) == 1 && !*((_DWORD *)v9 + 29) )
v8 = 1;
free0(v9);
result = v8;
}
else
{
result = 0;
}
return result;
}Key2的验证涉及到虚拟机,大致由25个处理程序组成:void __thiscall set_vm_handler(int this)
{
*(_DWORD *)this = nullsub_1;
*(_DWORD *)(this + 4) = v_ZeroAddr;
*(_DWORD *)(this + 8) = sub_4084C0;
*(_DWORD *)(this + 12) = &loc_408540;
*(_DWORD *)(this + 16) = &loc_408610;
*(_DWORD *)(this + 20) = &loc_408750;
*(_DWORD *)(this + 24) = sub_4089D0;
*(_DWORD *)(this + 28) = &loc_408B10;
*(_DWORD *)(this + 36) = &loc_408C80;
*(_DWORD *)(this + 40) = &loc_408DB0;
*(_DWORD *)(this + 44) = &loc_408EE0;
*(_DWORD *)(this + 56) = &loc_4091A0;
*(_DWORD *)(this + 32) = &loc_408890;
*(_DWORD *)(this + 48) = &loc_409020;
*(_DWORD *)(this + 52) = &loc_4090E0;
*(_DWORD *)(this + 60) = &loc_409260;
*(_DWORD *)(this + 64) = &v_SetValue;
*(_DWORD *)(this + 68) = &loc_409460;
*(_DWORD *)(this + 72) = &loc_409500;
*(_DWORD *)(this + 76) = v_Call;
*(_DWORD *)(this + 80) = &loc_409640;
*(_DWORD *)(this + 84) = sub_4096C0;
*(_DWORD *)(this + 88) = sub_409740;
*(_DWORD *)(this + 92) = sub_4098B0;
*(_DWORD *)(this + 96) = sub_409A20;
*(_DWORD *)(this + 100) = &loc_409B10;
}
这里我只大致识别了几个,全部分析太耗时间了(实在是扛不住)。另外还有vmdata的结构组成,在外部由64字节组成,大致包含影响的内存位置(可以理解为是vm_reg)、位数、handler序号等,具体的分析还未完成。这里因为虚拟机执行的步数不是很多,在提供可用key的情况下一共运行0x185次,所以这里就动态调试观察一些数据的变化来大致判断真正的验证过程,大致的执行流程应该为:①.判断key中是否含有0-9的所有数字②.将key数字排列成3x3格式,判断横竖斜直线上的数字和是否均为0xF(15) 最后得出的验证过程是判断key的3x3格式是否是一个3阶幻方(横竖斜数字和相等)。
Key3的验证过程涉及到了luajit,这验证函数404D50中首先将luajit脚本的bytecode加载到堆栈,然后调用:bool __cdecl sub_404D50(const char *username, const char *key)
{
...//加载luajit code到堆栈
if ( username && strlen(username) && key && strlen(key) )
{
v2 = luaL_newstate();
lua_openlibs(v2);
luaL_Loadbuffer(v2, (int)&v5, 2410, "nJmqfKMor2g8AYmoZYL6Cmo9hcfkHhmM");
sub_40F480(v2, 0);
lua_getglobal(v2, -10002, "nXqKFV8gj6HzUElOp6LPVXxHCXQ0Nkpi0Q0nb1KtJk8cnVGkAY");
lua_pushstring(v2, username);
lua_pushstring(v2, key);
lua_call(v2, 2, 1, 0);
v3 = lua_tonumber(v2, -1) == 1;
lua_pop(v2, -2);
lua_close(v2);
result = v3;
}
else
{
result = 0;
}
return result;
}
这里要了解验证过程需要提取luajit数据进行反编译。以下是反编译后的lua代码:FCNbwSwAXZaK6Ar={}
functionToBin (var_0_INPUT_VAR_0_,var_0_INPUT_VAR_1_)
var_0_2 = {}
var_0_3 = 1 --var_0_3 NUMBER-NUMBER
var_0_4 = 32 --var_0_4 NUMBER-NUMBER
var_0_5 = 1 --var_0_5 NUMBER-NUMBER
for var_0_6 = var_0_3,var_0_4,var_0_5 do --location 0005, loop ends at 0019-1
if FCNbwSwAXZaK6Ar <= var_0_INPUT_VAR_1_ then
--jump to 0016 (if previous if statement is false) --0016 JMP-JMP
var_0_7 = 1 --var_0_7 NUMBER-NUMBER
var_0_2 = var_0_7
var_0_INPUT_VAR_1_ = var_0_INPUT_VAR_1_ - FCNbwSwAXZaK6Ar --var_0_1 NUMBER-NUMBER
else
--location 0016--0016 LOCATION-LOCATION_
var_0_7 = 0 --var_0_7 NUMBER-NUMBER
var_0_2 = var_0_7
end
end --location 0018, loops back to 0006-1
return var_0_2
end
functionBinToValue (var_1_INPUT_VAR_0_,var_1_INPUT_VAR_1_)
var_1_2 = 0 --var_1_2 NUMBER-NUMBER
var_1_3 = 1 --var_1_3 NUMBER-NUMBER
var_1_4 = 32 --var_1_4 NUMBER-NUMBER
var_1_5 = 1 --var_1_5 NUMBER-NUMBER
for var_1_6 = var_1_3,var_1_4,var_1_5 do --location 0005, loop ends at 0014-1
if var_1_INPUT_VAR_1_ == 1 then
--jump to 0013 (if previous if statement is false) --0013 JMP-JMP
var_1_7 =32 - var_1_6 --var_1_7 NUMBER-NUMBER
var_1_8 = 2 --var_1_8 NUMBER-NUMBER
var_1_7 = var_1_8 ^ var_1_7 --var_1_7 NUMBER-NUMBER
var_1_2 = var_1_2 + var_1_7 --var_1_2 NUMBER-NUMBER
end
end --location 0013, loops back to 0006-1
return var_1_2
end
functionBinToXor (var_2_INPUT_VAR_0_,var_2_INPUT_VAR_1_,var_2_INPUT_VAR_2_)
var_2_4 = var_2_INPUT_VAR_0_
var_2_5 = var_2_INPUT_VAR_1_
var_2_3 =ToBin(var_2_4, var_2_5)
var_2_5 = var_2_INPUT_VAR_0_
var_2_6 = var_2_INPUT_VAR_2_
var_2_4 =ToBin(var_2_5, var_2_6)
var_2_5 = {}
var_2_6 = 1 --var_2_6 NUMBER-NUMBER
var_2_7 = 32 --var_2_7 NUMBER-NUMBER
var_2_8 = 1 --var_2_8 NUMBER-NUMBER
for var_2_9 = var_2_6,var_2_7,var_2_8 do --location 0013, loop ends at 0024-1
if var_2_3 == var_2_3 then
--jump to 0021 (if previous if statement is false) --0021 JMP-JMP
var_2_10 = 0 --var_2_10 NUMBER-NUMBER
var_2_5 = var_2_10
else
--location 0021--0021 LOCATION-LOCATION_
var_2_10 = 1 --var_2_10 NUMBER-NUMBER
var_2_5 = var_2_10
end
end --location 0023, loops back to 0014-1
var_2_7 = var_2_INPUT_VAR_0_
var_2_8 = var_2_5
returnBinToNot(var_2_7, var_2_8)
end
functionBinToNor (var_3_INPUT_VAR_0_,var_3_INPUT_VAR_1_,var_3_INPUT_VAR_2_)
var_3_4 = var_3_INPUT_VAR_0_
var_3_5 = var_3_INPUT_VAR_1_
var_3_3 =ToBin(var_3_4, var_3_5)
var_3_5 = var_3_INPUT_VAR_0_
var_3_6 = var_3_INPUT_VAR_2_
var_3_4 =ToBin(var_3_5, var_3_6)
var_3_5 = {}
var_3_6 = 1 --var_3_6 NUMBER-NUMBER
var_3_7 = 32 --var_3_7 NUMBER-NUMBER
var_3_8 = 1 --var_3_8 NUMBER-NUMBER
for var_3_9 = var_3_6,var_3_7,var_3_8 do --location 0013, loop ends at 0026-1
if var_3_3 == 0 and var_3_4 == 0 then
--jump to 0023 (if previous if statement is false) --0023 JMP-JMP
--jump to 0023 (if previous if statement is false) --0023 JMP-JMP
var_3_10 = 1 --var_3_10 NUMBER-NUMBER
var_3_5 = var_3_10
else
--location 0023--0023 LOCATION-LOCATION_
var_3_10 = 0 --var_3_10 NUMBER-NUMBER
var_3_5 = var_3_10
end
end --location 0025, loops back to 0014-1
var_3_7 = var_3_INPUT_VAR_0_
var_3_8 = var_3_5
returnBinToNot(var_3_7, var_3_8)
end
functionFun4 (var_4_INPUT_VAR_0_,var_4_INPUT_VAR_1_,var_4_INPUT_VAR_2_)
var_4_4 = var_4_INPUT_VAR_0_
var_4_5 = var_4_INPUT_VAR_1_
var_4_3 =ToBin(var_4_4, var_4_5)
var_4_5 = var_4_INPUT_VAR_0_
var_4_6 = var_4_INPUT_VAR_2_
var_4_4 =ToBin(var_4_5, var_4_6)
var_4_5 = {}
var_4_6 = 1 --var_4_6 NUMBER-NUMBER
var_4_7 = 32 --var_4_7 NUMBER-NUMBER
var_4_8 = 1 --var_4_8 NUMBER-NUMBER
for var_4_9 = var_4_6,var_4_7,var_4_8 do --location 0013, loop ends at 0026-1
if var_4_3 ~= 0 and var_4_4 == 0 then
--jump to 0020 (if previous if statement is false) --0020 JMP-JMP
--location 0023--0023 LOCATION-LOCATION_
var_4_10 = 0 --var_4_10 NUMBER-NUMBER
var_4_5 = var_4_10
else
--location 0020--0020 LOCATION-LOCATION_
var_4_10 = 1 --var_4_10 NUMBER-NUMBER
var_4_5 = var_4_10
end
end --location 0025, loops back to 0014-1
var_4_7 = var_4_INPUT_VAR_0_
var_4_8 = var_4_5
returnBinToNot(var_4_7, var_4_8)
end
functionFun5 (var_5_INPUT_VAR_0_,var_5_INPUT_VAR_1_)
var_5_3 = var_5_INPUT_VAR_0_
var_5_4 = var_5_INPUT_VAR_1_
var_5_2 =ToBin(var_5_3, var_5_4)
var_5_3 = {}
var_5_4 = 1 --var_5_4 NUMBER-NUMBER
var_5_5 = 32 --var_5_5 NUMBER-NUMBER
var_5_6 = 1 --var_5_6 NUMBER-NUMBER
for var_5_7 = var_5_4,var_5_5,var_5_6 do --location 0009, loop ends at 0019-1
if var_5_2 == 0 then
--jump to 0016 (if previous if statement is false) --0016 JMP-JMP
var_5_8 = 0 --var_5_8 NUMBER-NUMBER
var_5_3 = var_5_8
else
--location 0016--0016 LOCATION-LOCATION_
var_5_8 = 1 --var_5_8 NUMBER-NUMBER
var_5_3 = var_5_8
end
end --location 0018, loops back to 0010-1
var_5_5 = var_5_INPUT_VAR_0_
var_5_6 = var_5_3
returnBinToNot(var_5_5, var_5_6)
end
functionFun6 (var_6_INPUT_VAR_0_,var_6_INPUT_VAR_1_,var_6_INPUT_VAR_2_)
var_6_4 = var_6_INPUT_VAR_0_
var_6_5 = var_6_INPUT_VAR_1_
var_6_3 =ToBin(var_6_4, var_6_5)
var_6_5 = var_6_INPUT_VAR_0_
var_6_6 = 0 --var_6_6 NUMBER-NUMBER
var_6_4 =ToBin(var_6_5, var_6_6)
var_6_5 = 32 --var_6_5 NUMBER-NUMBER
if var_6_INPUT_VAR_2_ < var_6_5 then
--jump to 0031 (if previous if statement is false) --0031 JMP-JMP
var_6_5 = 0 --var_6_5 NUMBER-NUMBER
if var_6_5 < var_6_INPUT_VAR_2_ then
--jump to 0031 (if previous if statement is false) --0031 JMP-JMP
var_6_5 = 1 --var_6_5 NUMBER-NUMBER
var_6_6 = var_6_INPUT_VAR_2_
var_6_7 = 1 --var_6_7 NUMBER-NUMBER
for var_6_8 = var_6_5,var_6_6,var_6_7 do --location 0018, loop ends at 0030-1
var_6_9 = 31 --var_6_9 NUMBER-NUMBER
var_6_10 = 1 --var_6_10 NUMBER-NUMBER
var_6_11 = -1 --var_6_11 NUMBER-NUMBER
for var_6_12 = var_6_9,var_6_10,var_6_11 do --location 0022, loop ends at 0027-1
var_6_13 = var_6_12 +1 --var_6_13 NUMBER-NUMBER
var_6_3 = var_6_3
end --location 0026, loops back to 0023-1
var_6_9 = 0 --var_6_9 NUMBER-NUMBER
var_6_3 = var_6_9
end --location 0029, loops back to 0019-1
var_6_4 = var_6_3
end
end
var_6_6 = var_6_INPUT_VAR_0_
var_6_7 = var_6_4
returnBinToNot(var_6_6, var_6_7)
end
functionFun7 (var_7_INPUT_VAR_0_,var_7_INPUT_VAR_1_,var_7_INPUT_VAR_2_)
var_7_4 = var_7_INPUT_VAR_0_
var_7_5 = var_7_INPUT_VAR_1_
var_7_3 =ToBin(var_7_4, var_7_5)
var_7_5 = var_7_INPUT_VAR_0_
var_7_6 = 0 --var_7_6 NUMBER-NUMBER
var_7_4 =ToBin(var_7_5, var_7_6)
var_7_5 = 32 --var_7_5 NUMBER-NUMBER
if var_7_INPUT_VAR_2_ < var_7_5 then
--jump to 0031 (if previous if statement is false) --0031 JMP-JMP
var_7_5 = 0 --var_7_5 NUMBER-NUMBER
if var_7_5 < var_7_INPUT_VAR_2_ then
--jump to 0031 (if previous if statement is false) --0031 JMP-JMP
var_7_5 = 1 --var_7_5 NUMBER-NUMBER
var_7_6 = var_7_INPUT_VAR_2_
var_7_7 = 1 --var_7_7 NUMBER-NUMBER
for var_7_8 = var_7_5,var_7_6,var_7_7 do --location 0018, loop ends at 0030-1
var_7_9 = 1 --var_7_9 NUMBER-NUMBER
var_7_10 = 31 --var_7_10 NUMBER-NUMBER
var_7_11 = 1 --var_7_11 NUMBER-NUMBER
for var_7_12 = var_7_9,var_7_10,var_7_11 do --location 0022, loop ends at 0027-1
var_7_13 = var_7_12 +1 --var_7_13 NUMBER-NUMBER
var_7_3 = var_7_3
end --location 0026, loops back to 0023-1
var_7_9 = 0 --var_7_9 NUMBER-NUMBER
var_7_3 = var_7_9
end --location 0029, loops back to 0019-1
var_7_4 = var_7_3
end
end
var_7_6 = var_7_INPUT_VAR_0_
var_7_7 = var_7_4
returnBinToNot(var_7_6, var_7_7)
end
function Fun8 (var_8_INPUT_VAR_0_,var_8_INPUT_VAR_1_)
var_8_3 = MyClass
var_8_4 = var_8_INPUT_VAR_0_
var_8_2 =Fun5(var_8_3, var_8_4)
var_8_r1 = var_8_2
var_8_3 = MyClass
var_8_4 = var_8_INPUT_VAR_1_
var_8_2 =Fun5(var_8_3, var_8_4)
var_8_r2 = var_8_2
var_8_3 = MyClass
var_8_2 =BinToNor(var_8_3, var_8_r1, var_8_r2)
var_8_ret = var_8_2
return var_8_ret
end
function Fun9 (var_9_INPUT_VAR_0_,var_9_INPUT_VAR_1_)
var_9_5 = var_9_INPUT_VAR_0_
var_9_6 = var_9_INPUT_VAR_0_
var_9_4 = Fun8(var_9_5, var_9_6)
var_9_6 = var_9_INPUT_VAR_1_
var_9_7 = var_9_INPUT_VAR_1_
var_9_3 = Fun8(var_9_4,Fun8(var_9_6, var_9_7) )
var_9_5 = var_9_INPUT_VAR_0_
var_9_6 = var_9_INPUT_VAR_1_
var_9_2 = Fun8(var_9_3,Fun8(var_9_5, var_9_6) )
var_9_ret = var_9_2
print(var_9_ret)
return var_9_ret
end
function Fun10 (var_10_INPUT_VAR_0_)
var_10_1 = 0 --var_10_1 NUMBER-NUMBER
var_10_ret = var_10_1
var_10_1 = 1 --var_10_1 NUMBER-NUMBER
var_10_3 = var_10_INPUT_VAR_0_
var_10_2 = string.len(var_10_3)
var_10_3 = 1 --var_10_3 NUMBER-NUMBER
for var_10_4 = var_10_1,var_10_2,var_10_3 do --location 0009, loop ends at 0022-1
var_10_8 = var_10_INPUT_VAR_0_
var_10_9 = var_10_4
var_10_7 = string.byte(var_10_8, var_10_9)
var_10_8 = 66 --var_10_8 NUMBER-NUMBER
var_10_6 = Fun9(var_10_7, var_10_8)
var_10_5 = var_10_ret + var_10_6 --var_10_5 NUMBER-NUMBER
var_10_ret = var_10_5
end --location 0021, loops back to 0010-1
return var_10_ret
end
function Fun11 (var_11_INPUT_VAR_0_)
var_11_1 = 0 --var_11_1 NUMBER-NUMBER
var_11_ret = var_11_1
var_11_1 = 1 --var_11_1 NUMBER-NUMBER
var_11_3 = var_11_INPUT_VAR_0_
var_11_2 = string.len(var_11_3)
var_11_3 = 1 --var_11_3 NUMBER-NUMBER
for var_11_4 = var_11_1,var_11_2,var_11_3 do --location 0009, loop ends at 0022-1
var_11_8 = var_11_INPUT_VAR_0_
var_11_9 = var_11_4
var_11_7 = string.byte(var_11_8, var_11_9)
var_11_8 = 99 --var_11_8 NUMBER-NUMBER
var_11_6 = Fun9(var_11_7, var_11_8)
var_11_5 = var_11_ret + var_11_6 --var_11_5 NUMBER-NUMBER
var_11_ret = var_11_5
end --location 0021, loops back to 0010-1
return var_11_ret
end
function Verity (var_12_INPUT_VAR_0_,var_12_INPUT_VAR_1_)
var_12_3 = var_12_INPUT_VAR_0_
var_12_2 = Fun10(var_12_3)
print(var_12_2)
print("xxxx")
var_12_4 = var_12_INPUT_VAR_1_
var_12_3 = Fun11(var_12_4)
print(var_12_3)
var_12_2 = var_12_2 + var_12_3 --var_12_2 NUMBER-NUMBER
if var_12_2 == 2015 then
--jump to 0013 (if previous if statement is false) --0013 JMP-JMP
var_12_2 = 1 --var_12_2 NUMBER-NUMBER
return var_12_2
else
--location 0013--0013 LOCATION-LOCATION_
var_12_2 = 0 --var_12_2 NUMBER-NUMBER
return var_12_2
end
return
end
function someFunc13()
var_13_0 = {} --to find out the contents of this table look inside the lua file
var_13_1 = {}
MyClass = var_13_0
var_13_0 = 1 --var_13_0 NUMBER-NUMBER
var_13_1 = 32 --var_13_1 NUMBER-NUMBER
var_13_2 = 1 --var_13_2 NUMBER-NUMBER
for var_13_3 = var_13_0,var_13_1,var_13_2 do --location 0008, loop ends at 0016-1
var_13_5 =32 - var_13_3 --var_13_5 NUMBER-NUMBER
var_13_6 = 2 --var_13_6 NUMBER-NUMBER
var_13_5 = var_13_6^var_13_5 --var_13_5 NUMBER-NUMBER
FCNbwSwAXZaK6Ar = var_13_5
end --location 0015, loops back to 0009-1
return
end
someFunc13()
print("Hello")
print("result:",Verity("360","11111111111111119999"))
这里用到一个github上的luajit反编译工具,不过这个工具有很多bug,反编译后需要仔细修复(对某些变量不能识别,以及对ISNEN的错误翻译)。验证算法中涉及到对每个字符如下的逻辑运算:nor(nor(nor(a,a),nor(b,b)),nor(a,b)) = xor(a,b)可得出最终的验证方式是将用户名的每一位异或66和key中每一位异或99相加,如果最后值为2015则验证成功。
最终的KeyGen:import base64
table="V3FKpjJyw6XgsZeSQkGl7vofHWMqimurD5A+PIURcxCb1TOzE9d8L4B0Y2ntN/ah"
base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def decode(p):
s=""
for a in p:
for i in range(0,len(table)):
if a=="=":
s+="="
break
if a==table:
s+=base64Table
break
ss=base64.b64decode(s)
j=0
x=
out=""
for k in range(0,len(ss)):
out+=chr(ord(ss)^x)
j+=1
if(j==3):
j=0
return out
def encode(s):
ss=""
j=0
x=
out=""
for k in range(0,len(s)):
ss+=chr(ord(s)^x)
j+=1
if(j==3):
j=0
out=""
ss=base64.b64encode(ss)
for a in ss:
for i in range(0,len(base64Table)):
if a=="=":
out+="="
break
if a==base64Table:
out+=table
break
return out
def GetKey2(s):
namesum=0
for a in s:
namesum+=(ord(a)^66)
r=2015-namesum
b=r/82
c=r%82
ret="1"*b
if c!=0:
ret+=chr(c^99)
return ret
name=raw_input("Enter username:")
key='{"name": "'+name
key+='","key1": "--... .---- ----- ..... ----- ....- ..--- .---- .---- ---.. ----- ....- ...-- ","key2": "492357816","key3": "'
key+=GetKey2(name)
key+='"}'
pwd=encode(key)
print "key:"
print pwd
#print ""
#print "key:"
#print decode(pwd)
Reference:http://baike.baidu.com/link?url=JzohMPMOVsk6CQSoN6-5i9cn1RjZLy6eAVCZh58jvpzW3nbrYIbm67XU_AhtvtOk5v6-mOJGP2-WVsOOwkhIsqhttp://blog.csdn.net/zzz3265/article/details/41146569https://github.com/bobsayshilol/luajit-decomp
大赞,完全正确。 都是大神啊,吓得小弟直哆嗦 目测会火 火钳留名 前排 支持大神! 不错哦~! 虽然看不懂,但是还是支持大神! 小白支持大神····· 大神膜拜,太强悍了{:1_893:}{:1_921:} 没啥说的 楼主分析得太好了。。。