吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 24837|回复: 106
收起左侧

[原创] 吾爱破解安全大赛cm6分析

  [复制链接]
〇〇木一 发表于 2016-3-30 13:05

程序通过创建新的线程来完成验证工作:
[C] 纯文本查看 复制代码
 if ( (unsigned __int16)a3 == 1001 )
      {
        ThreadId = 0;
        CreateThread(0, 0, StartAddress, lpParameter, 0, (LPDWORD)&ThreadId);
        return 0;
      }

其中serial是通过变形的base64算法加密的,在base64算法43的过程中对每字节分别进行异或:
[C] 纯文本查看 复制代码
v8 = (4 * (_BYTE)v + ((BYTE1(v) >> 4) & 3)) ^ 0x4C;
        v9 = (16 * BYTE1(v) + ((BYTE2(v) >> 2) & 0xF)) ^ 0x43;
        v17[v18 + 2] = (BYTE3(v) + (BYTE2(v) << 6)) ^ 0x47;
v17[v18] = v8;
        v17[v18 + 1] = v9;

真正的serial将由4部分组成,竞赛时提供的key 解密后的内容:
[Asm] 纯文本查看 复制代码
{[/align]  "name": "360",
  "key1": "--... .---- ----- ..... ----- ....- ..--- .---- .---- ---.. ----- ....- ...-- ",
  "key2": "492357816",
  "key3": "11111111111111119999"
}


第一部分name应与username相同。
接下来的3key分别对应3个验证函数,只有都验证通过才算成功。


Key1是摩斯电码,解密后的值为7105042118043。以下是验证函数:
[C] 纯文本查看 复制代码
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; // [sp+18h] [bp-28h]@8
  int v11; // [sp+19h] [bp-27h]@8
  int v12; // [sp+1Dh] [bp-23h]@8
  char v13; // [sp+21h] [bp-1Fh]@8
  char key1_10_?; // [sp+24h] [bp-1Ch]@8
  int v15; // [sp+25h] [bp-1Bh]@8
  int v16; // [sp+29h] [bp-17h]@8
  char v17; // [sp+2Dh] [bp-13h]@8
  CHAR v18; // [sp+30h] [bp-10h]@13
  int v19; // [sp+31h] [bp-Fh]@13
  int v20; // [sp+35h] [bp-Bh]@13
  __int16 v21; // [sp+39h] [bp-7h]@13
  char v22; // [sp+3Bh] [bp-5h]@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_110000000000-89999999999之间,且包含0-9所有数字

写一个脚本就能获取到很多这样的数字:
[Python] 纯文本查看 复制代码
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的验证就有些复杂了,以下是验证部分:
[C] 纯文本查看 复制代码
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; // [sp+Ch] [bp-Ch]@3
  unsigned int v12; // [sp+10h] [bp-8h]@3
  unsigned int v13; // [sp+14h] [bp-4h]@3

  if ( key2 && strlen(key2) == 9 )
  {
    v2 = 1;
    v13 = 0;
    v3 = 0;
    v12 = 0;
    v11 = 0;
    do
    {
      v4 = key2[v3];
      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个处理程序组成:
[Asm] 纯文本查看 复制代码
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格式,判断横竖斜直线上的数字和是否均为0xF15
最后得出的验证过程是判断key3x3格式是否是一个3阶幻方(横竖斜数字和相等)。

Key3的验证过程涉及到了luajit,这验证函数404D50中首先将luajit脚本的bytecode加载到堆栈,然后调用:
[C] 纯文本查看 复制代码
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代码:
[Python] 纯文本查看 复制代码
FCNbwSwAXZaK6Ar={}
function  ToBin (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_6] <= 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_6] = var_0_7
			var_0_INPUT_VAR_1_ = var_0_INPUT_VAR_1_ - FCNbwSwAXZaK6Ar[var_0_6] --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_6] = var_0_7
		end
	end --location 0018, loops back to 0006-1
	return var_0_2
end


function  BinToValue (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_[var_1_6] == 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


function  BinToXor (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_9] == var_2_3[var_2_9] 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_9] = var_2_10
		else
			--location 0021--0021 LOCATION-LOCATION_
			var_2_10 = 1 --var_2_10 NUMBER-NUMBER
			var_2_5[var_2_9] = 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
	return  BinToNot(var_2_7, var_2_8)
end


function  BinToNor (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[var_3_9] == 0 and var_3_4[var_3_9] == 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_9] = var_3_10
		else
			--location 0023--0023 LOCATION-LOCATION_
			var_3_10 = 0 --var_3_10 NUMBER-NUMBER
			var_3_5[var_3_9] = 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
	return  BinToNot(var_3_7, var_3_8)
end


function  Fun4 (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[var_4_9] ~= 0 and var_4_4[var_4_9] == 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_9] = var_4_10
		else
			--location 0020--0020 LOCATION-LOCATION_
			var_4_10 = 1 --var_4_10 NUMBER-NUMBER
			var_4_5[var_4_9] = 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
	return  BinToNot(var_4_7, var_4_8)
end


function  Fun5 (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[var_5_7] == 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_7] = var_5_8
		else
			--location 0016--0016 LOCATION-LOCATION_
			var_5_8 = 1 --var_5_8 NUMBER-NUMBER
			var_5_3[var_5_7] = 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
	return  BinToNot(var_5_5, var_5_6)
end


function  Fun6 (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_13] = var_6_3[var_6_12]
				end --location 0026, loops back to 0023-1
				var_6_9 = 0 --var_6_9 NUMBER-NUMBER
				var_6_3[1] = 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
	return  BinToNot(var_6_6, var_6_7)
end


function  Fun7 (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_12] = var_7_3[var_7_13]
				end --location 0026, loops back to 0023-1
				var_7_9 = 0 --var_7_9 NUMBER-NUMBER
				var_7_3[32] = 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
	return  BinToNot(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_3] = 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)
可得出最终的验证方式是将用户名的每一位异或66key中每一位异或99相加,如果最后值为2015则验证成功。


最终的KeyGen
[Python] 纯文本查看 复制代码
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[i]:
				s+=base64Table[i]
				break
	ss=base64.b64decode(s)
	j=0
	x=[0x4C,0x43,0x47]
	out=""
	for k in range(0,len(ss)):
		out+=chr(ord(ss[k])^x[j])
		j+=1
		if(j==3):
			j=0
	return out

def encode(s):
	ss=""
	j=0
	x=[0x4C,0x43,0x47]
	out=""
	for k in range(0,len(s)):
		ss+=chr(ord(s[k])^x[j])
		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[i]:
				out+=table[i]
				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-WVsOOwkhIsq
http://blog.csdn.net/zzz3265/article/details/41146569
https://github.com/bobsayshilol/luajit-decomp


免费评分

参与人数 45热心值 +45 收起 理由
GG0 + 1 我很赞同!
Mr.Mlwareson_V + 1 谢谢@Thanks!
联盟.视频制作v + 1 热心回复!
Pinatapai + 1 我很赞同!
有你的远方 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
dragndrop + 1 谢谢@Thanks!
Hyabcd + 1 谢谢@Thanks!
bitssly + 1 用心讨论,共获提升!
do141414 + 1 我很赞同!
wbphs + 1 不得不说牛的不行了
choke + 1 我很赞同!
Lnairan + 1 谢谢@Thanks!
yjyu2000 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
LOVE_TT + 1 6的不行啊 可惜没有OD里面的东西 结合一下.
freedev100 + 1 谢谢@Thanks!
自恋我心i + 1 膜拜大牛
sirius_yy + 1 跪拜!大神的脑子确实灵光,小白以绕晕!
不懂破解 + 1 支持下+捧个场
hack_koko + 1 已跪拜
无极166 + 1 谢谢@Thanks!
偷奶酪的老鼠 + 1 大神,求签名
292219828 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
Tortoise + 1 谢谢@Thanks!
xugong + 1 谢谢@Thanks!
丶小明 + 1 谢谢@Thanks!
梦游枪手 + 1 摩斯电码啥都上了,这让我等小白情何以堪
1434930788 + 1 大神,求签名
vigers + 1 大腿又粗了几分
独孤唐 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
yypE + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
z491749617 + 1 大神好 大神好
Terrorblade + 1 我很赞同!
bestyyb + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
FraMeQ + 1 谢谢@Thanks!
-Zing- + 1 这么厉害应该有个论坛大牛的认证
mrwinner + 1 谢谢@Thanks!
renfeng + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
苏紫方璇 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
海盗小K + 1 WoodOne太厉害。。。
idenny7 + 1 谢谢@Thanks!
四季折之羽 + 1 大神,抱抱。。
tcpcm + 1 谢谢@Thanks!
蚯蚓翔龙 + 1 谢谢@Thanks!
WildWolf + 1 谢谢@Thanks!
wzxkk123 + 1 感谢分享哦

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

ximo 发表于 2016-3-30 13:21
大赞,完全正确。

免费评分

参与人数 1热心值 +1 收起 理由
Srao + 1 我很赞同!

查看全部评分

头像被屏蔽
相守 发表于 2016-3-30 14:01
625236846 发表于 2016-3-30 13:44
头像被屏蔽
L精神往上走 发表于 2016-3-30 13:49
前排   支持大神!
Nisy 发表于 2016-3-30 13:52
不错哦~!

免费评分

参与人数 1热心值 +1 收起 理由
凉米饭 + 1 只因心情不好

查看全部评分

失业 发表于 2016-3-30 13:57
虽然看不懂,但是还是支持大神!

免费评分

参与人数 1热心值 +1 收起 理由
凉米饭 + 1 只因心情不好

查看全部评分

皇冠 发表于 2016-3-30 13:57
小白支持大神·····

免费评分

参与人数 1热心值 +1 收起 理由
凉米饭 + 1 只因心情不好

查看全部评分

神话eric 发表于 2016-3-30 13:58
大神膜拜,太强悍了
苏紫方璇 发表于 2016-3-30 14:02
没啥说的   楼主分析得太好了。。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 10:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表