首页
社区
课程
招聘
[原创]看雪CTF2019晋级赛Q1 第7题
发表于: 2019-3-22 16:36 5943

[原创]看雪CTF2019晋级赛Q1 第7题

2019-3-22 16:36
5943

 计算出2个常数 ,我们称之为 constKey1 ,constKey2,如下:

4BC080 该值为: 0x1093ACBD

         4BC084 该值为:  0x2cF346

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

1)根据上面得到的索引值(0x14 0x13 ...),从之前生成的510个buf中,获取2个数值,一个为index,一个为keyvalue.

2)根据index,索引g_sntable,得到另外一个索引index2

3) 根据index2 对全局变量off_4BC060指针进行索引,得到一个数值为 constKey

4) 判断constKey 与前面的keyvalue是否相等,如果相等,则equCnt++

5) 如果 index的值等于0x28则 将equCnt--,进行下一次循环

6) 如果  index  > 0x28 则 index --

7)整个循环0x51次数。

然后利用上面的 equCnt 对 off_4BC05C进行索引并计算checksun数值,  判断checksum是否等于 0x1F1A, 如果不等于则 输入sn错误,直接退出。如果相等,则利用equCnt的数值对off_4BC05C进行解密,然后将解密后的数据打印输出。

(写的比较多。。。。)
一、去掉混淆和程序修改检测                                           
1、程序加入了混淆代码,分析起来比较费劲,先把混淆bypass掉。代码如下:

void ByPassOb( void )
{
	char		box[1024];
	int		size;
	int		start		= 0x1000;
	int		end		= 0xBC000;
	unsigned char	jmp_code[16][4] =
	{
		0x7A, 0x03, 0x7B, 0x01,
		0x77, 0x03, 0x76, 0x01,
		0x71, 0x03, 0x70, 0x01,
		0x7C, 0x03, 0x7D, 0x01,
		0x70, 0x03, 0x71, 0x01,
		0x7F, 0x03, 0x7E, 0x01,
		0x78, 0x03, 0x79, 0x01,
		0x75, 0x03, 0x74, 0x01,
		0x7B, 0x03, 0x7A, 0x01,
		0x72, 0x03, 0x73, 0x01,
		0x7D, 0x03, 0x7C, 0x01,
		0x74, 0x03, 0x75, 0x01,
		0x76, 0x03, 0x77, 0x01,
		0x79, 0x03, 0x78, 0x01,
		0x7e, 0x03, 0x7f, 0x01,
		0x73, 0x03, 0x72, 0x01,
	};
	unsigned char	call_code1[5]	= { 0xE8, 0x02, 0x00, 0x00, 0x00 };
	unsigned char	call_code11[5]	= { 0xE8, 0x03, 0x00, 0x00, 0x00 };
	unsigned char	call_code12[5]	= { 0xE8, 0x01, 0x00, 0x00, 0x00 };
	unsigned char	call_code13[6]	= { 0x50, 0xE8, 0x01, 0x00, 0x00, 0x00 };
	unsigned char	call_code15[5]	= { 0xE8, 0x04, 0x00, 0x00, 0x00 };
	unsigned char	call_code2[3]	= { 0x83, 0xC4, 0x04 };
	unsigned char	call_code21[5]	= { 0x83, 0x04, 0x24, 0x06, 0xC3 };
	unsigned char	call_code23[2]	= { 0x58, 0x58 };
	unsigned char	call_code24[1]	= { 0x58 };
	unsigned char	call_code25[2]	= { 0xeb, 0x0c };
	unsigned char	jmp_code1[4]	= { 0x7c, 0x03, 0xeb, 0x03 };
	unsigned char	jmp_code2[2]	= { 0x74, 0xFB };
	unsigned char	stcjb_code[3]	= { 0xF9, 0x72, 0x02 };
	unsigned char	clcjnb_code[3]	= { 0xF8, 0x73, 0x02 };
	unsigned char	clcjnb_code1[3] = { 0xF8, 0x73, 0x01 };

	unsigned char	main_code[15]		= { 0xC6, 0x55, 0x5F, 0xF3, 0x00, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xA2, 0x0C, 0x83, 0xC4, 0x04 };
	unsigned char	change_code[0x14]	= { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
	unsigned char	main_stack_code1[]	= { 0x83, 0xec, 0x0c };
	unsigned char	jmpEax_code[3]		= { 0x40, 0xEB, 0x01 };
	unsigned char	jmpEax_code2[2]		= { 0xFF, 0xE0 };

	unsigned char* buf = GetFileNameBuffer( "DancingCircle.exe", &size );

	/* bypass 随机数 */
	buf[0xF77]	= 0xEB;
	buf[0xF78]	= 0x47;

	/* by pass anti debug */
	buf[0xB8798]			= 0x33;
	buf[0xB8799]			= 0xc0;
	*(int *) (buf + 0xBB31D)	= 0x24230201;

	/* bp pass main开始4B8DFA地址的混淆代码 */
	memcpy( buf + 0x99f, change_code, 5 );

	/* 使部分函数F5 OK */
	memcpy( buf + 0xb81e8, main_stack_code1, 3 );
	memcpy( buf + 0xb81fa, change_code, 5 );

	int	findJmpCnt	= 0;
	int	findCallCnt	= 0;
	int	findMainCnt	= 0;
	int	findStcjbCnt	= 0;
	int	findClcjnbCnt	= 0;

	/* 分析代码段,bypass混淆代码 */
	for ( int i = start; i < end; i++ )
	{
		if ( 0 == memcmp( buf + i, main_code, 15 ) )
		{
			memcpy( buf + i, change_code, 15 );
			i = i + 14;
			findMainCnt++;
		}
		if ( 0 == memcmp( buf + i, stcjb_code, 3 ) )
		{
			memcpy( buf + i, change_code, 5 );
			i = i + 4;
			findStcjbCnt++;
		}
		if ( 0 == memcmp( buf + i, clcjnb_code, 3 ) )
		{
			memcpy( buf + i, change_code, 5 );
			i = i + 4;
			findClcjnbCnt++;
		}

		if ( 0 == memcmp( buf + i, clcjnb_code1, 3 ) )
		{
			memcpy( buf + i, change_code, 4 );
			i = i + 3;
			findClcjnbCnt++;
		}
		if ( 0 == memcmp( buf + i, call_code1, 5 ) )
		{
			if ( 0 == memcmp( buf + i + 7, call_code2, 3 ) )
			{
				memcpy( buf + i, change_code, 10 );
				i = i + 9;
				findCallCnt++;
				continue;
			}
		}

		if ( 0 == memcmp( buf + i, call_code11, 5 ) )
		{
			if ( 0 == memcmp( buf + i + 8, call_code2, 3 ) )
			{
				memcpy( buf + i, change_code, 11 );
				i = i + 10;
				findCallCnt++;
				continue;
			}
			if ( 0 == memcmp( buf + i + 8, call_code24, 1 ) )
			{
				memcpy( buf + i, change_code, 9 );
				i = i + 8;
				findCallCnt++;
				continue;
			}
		}
		if ( 0 == memcmp( buf + i, call_code12, 5 ) )
		{
			if ( 0 == memcmp( buf + i + 6, call_code2, 3 ) )
			{
				memcpy( buf + i, change_code, 9 );
				i = i + 8;
				findCallCnt++;
				continue;
			}

			if ( 0 == memcmp( buf + i + 6, call_code21, 5 ) )
			{
				memcpy( buf + i, change_code, 11 );
				i = i + 10;
				findCallCnt++;
				continue;
			}
		}

		if ( 0 == memcmp( buf + i, call_code13, 6 ) )
		{
			if ( 0 == memcmp( buf + i + 7, call_code23, 2 ) )
			{
				memcpy( buf + i, change_code, 9 );
				i = i + 7;
				findCallCnt++;
				continue;
			}
		}
		if ( 0 == memcmp( buf + i, call_code15, 5 ) )
		{
			if ( 0 == memcmp( buf + i + 6, call_code25, 2 ) )
			{
				memcpy( buf + i, change_code, 0x14 );
				i = i + 0x13;
				findCallCnt++;
			}
		}
		if ( 0 == memcmp( buf + i, jmp_code1, 4 ) )
		{
			if ( 0 == memcmp( buf + i + 5, jmp_code2, 2 ) )
			{
				memcpy( buf + i, change_code, 7 );
				i = i + 6;
				findJmpCnt++;
				continue;
			}
		}
		if ( 0 == memcmp( buf + i, jmpEax_code, 3 ) )
		{
			if ( 0 == memcmp( buf + i + 4, jmpEax_code2, 2 ) )
			{
				memcpy( buf + i, change_code, 6 );
				i = i + 6;
				findJmpCnt++;
				continue;
			}
		}
		for ( int j = 0; j < 16; j++ )
		{
			if ( 0 == memcmp( buf + i, jmp_code[j], 4 ) )
			{
				memcpy( buf + i, change_code, 5 );
				i = i + 4;
				findJmpCnt++;
				break;
			}
		}
	}
	unlink( "DancingCircle-bypassob.exe" );
	WriteFileNameBuffer( "DancingCircle-bypassob.exe", buf, size );
}
去掉混淆后代码如下:
.text:00401F58                                     ChangeKeyByAddr proc near               ; CODE XREF: sub_4025D3+1A↓p
.text:00401F58                                                                             ; ChangeKeyAndAntiDebug+25↓p
.text:00401F58                                                                             ; _main+71↓p
.text:00401F58                                                                             ; DATA XREF: sub_4025D3+13↓o
.text:00401F58
.text:00401F58                                     arg_0           = dword ptr  8
.text:00401F58                                     arg_4           = dword ptr  0Ch
.text:00401F58
.text:00401F58 55                                                  push    ebp
.text:00401F59 89 E5                                               mov     ebp, esp
.text:00401F5B 60                                                  pusha
.text:00401F5C 9C                                                  pushf
.text:00401F5D BA 80 C0 4B 00                                      mov     edx, offset source
.text:00401F62 90                                                  nop
.text:00401F63 90                                                  nop
.text:00401F64 90                                                  nop
.text:00401F65 90                                                  nop
.text:00401F66 90                                                  nop
.text:00401F67 90                                                  nop
.text:00401F68 90                                                  nop

int __usercall ChangeKeyByAddr@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>, _DWORD *a4, int a5)
{
  unsigned int v5; // et0
  _DWORD *v6; // esi
  int v7; // ecx
  _DWORD *v8; // esi
  int v9; // eax
  int v10; // eax
  unsigned int v12; // [esp-24h] [ebp-24h]
  int v13; // [esp-18h] [ebp-18h]
  int v14; // [esp-4h] [ebp-4h]
  int savedregs; // [esp+0h] [ebp+0h]
  _DWORD *retaddr; // [esp+4h] [ebp+4h]

  v14 = a3;
  v13 = a2;
  v5 = __readeflags();
  v12 = v5;
  v6 = a4;
  v7 = a5;
  if ( !a4 )
    v6 = retaddr;
  v8 = (_DWORD *)((char *)v6 + 5);
  v9 = 0;
  do
  {
    v10 = *v8 ^ v9;
    ++v8;
    v9 = __ROR4__(v10 ^ 0x78563412, 9);
    --v7;
  }
  while ( v7 );
  *(_DWORD *)(&source + *((unsigned __int8 *)retaddr + 4)) = *retaddr ^ v9;
  __writeeflags(v12);
  savedregs = v14;
  retaddr = (_DWORD *)((char *)retaddr + 5);
  return nullsub_2(v13, a1);
}
3、关键key生成函数 401F58(如上)
.text:00401F58                                     ChangeKeyByAddr proc near               ; CODE XREF: sub_4025D3+1A↓p
.text:00401F58                                                                             ; ChangeKeyAndAntiDebug+25↓p
.text:00401F58                                                                             ; _main+71↓p
.text:00401F58                                                                             ; DATA XREF: sub_4025D3+13↓o
.text:00401F58
.text:00401F58                                     arg_0           = dword ptr  8
.text:00401F58                                     arg_4           = dword ptr  0Ch
.text:00401F58
.text:00401F58 55                                                  push    ebp
.text:00401F59 89 E5                                               mov     ebp, esp
.text:00401F5B 60                                                  pusha
.text:00401F5C 9C                                                  pushf
.text:00401F5D BA 80 C0 4B 00                                      mov     edx, offset source
.text:00401F62 90                                                  nop
.text:00401F63 90                                                  nop
.text:00401F64 90                                                  nop
.text:00401F65 90                                                  nop
.text:00401F66 90                                                  nop
.text:00401F67 90                                                  nop
.text:00401F68 90                                                  nop

int __usercall ChangeKeyByAddr@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>, _DWORD *a4, int a5)
{
  unsigned int v5; // et0
  _DWORD *v6; // esi
  int v7; // ecx
  _DWORD *v8; // esi
  int v9; // eax
  int v10; // eax
  unsigned int v12; // [esp-24h] [ebp-24h]
  int v13; // [esp-18h] [ebp-18h]
  int v14; // [esp-4h] [ebp-4h]
  int savedregs; // [esp+0h] [ebp+0h]
  _DWORD *retaddr; // [esp+4h] [ebp+4h]

  v14 = a3;
  v13 = a2;
  v5 = __readeflags();
  v12 = v5;
  v6 = a4;
  v7 = a5;
  if ( !a4 )
    v6 = retaddr;
  v8 = (_DWORD *)((char *)v6 + 5);
  v9 = 0;
  do
  {
    v10 = *v8 ^ v9;
    ++v8;
    v9 = __ROR4__(v10 ^ 0x78563412, 9);
    --v7;
  }
  while ( v7 );
  *(_DWORD *)(&source + *((unsigned __int8 *)retaddr + 4)) = *retaddr ^ v9;
  __writeeflags(v12);
  savedregs = v14;
  retaddr = (_DWORD *)((char *)retaddr + 5);
  return nullsub_2(v13, a1);
}
3、关键key生成函数 401F58(如上)
程序去掉混淆后,使得401F58计算的checksum有误,因此在后面需要修正。
程序共三处调用401F58
程序去掉混淆后,使得401F58计算的checksum有误,因此在后面需要修正。
程序共三处调用401F58
1)计算main函数的checksum,放入到全局变量中4BC080 该值为: 0x1093ACBD
1)计算main函数的checksum,放入到全局变量中4BC080 该值为: 0x1093ACBD
2)计算4025D3反调试函数的checksum,放入到全局变量中4BC084 该值为0x2cF346
2)计算4025D3反调试函数的checksum,放入到全局变量中4BC084 该值为0x2cF346
3)计算401F58本身的checksum,并放入到 0x4BC080+0x9D位置, 该值为 0x24230201
3)计算401F58本身的checksum,并放入到 0x4BC080+0x9D位置, 该值为 0x24230201
#coding=utf-8

import struct
from idaapi import *
from idc import *
from idautils import *

'''====================================================
函数名:GetLibAddr
用  途:根据模块名获得模块起始地址
备  注:此函数在SHT被破坏时将不起作用
====================================================='''
def GetLibAddr(targetName):
    targetBase = 0
    for i in Modules():
        #print i.name
        if targetName in i.name:
            targetBase = int("%x"%(i.base), 16)
            #print 'targetName:=' + targetName + 'targetBase:=' + str(targetBase)
            break
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False

    return targetBase

'''====================================================
函数名:GetSegAddrByName
用  途:根据段名获得段的起始地址
备  注:
====================================================='''
def GetSegAddrByName(targetName):
    tempAddr = FirstSeg()
    while tempAddr!=0:
        if tempAddr == 0:
            break
        name = SegName(tempAddr)
        if targetName in name:
            return tempAddr
        tempAddr = NextSeg(tempAddr)
    return 0

'''====================================================
函数名:writeMemoryForAddr
用  途:向模块地址写入指定shellcode
备  注:
====================================================='''
def writeMemoryForAddr(targetName, offset, buf):
    targetBase = 0
    targetBase = GetSegAddrByName(targetName)
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False

    addr = targetBase + offset
    if not dbg_write_memory(addr, buf):
        return False

    refresh_debugger_memory()
    return True

'''====================================================
函数名:addBptForAddr
用  途:给模块指定偏移下断点
备  注:
====================================================='''
def addBptForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        SetBptAttr(soAddr + offset, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
        MakeComm(soAddr + offset, comm)
    else :
        print 'create point fail'
    return True

'''====================================================
函数名:DelBptForAddr
用  途:删除模块指定偏移的断点
备  注:
====================================================='''
def DelBptForAddr(targetName, offset):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        DelBpt(soAddr + offset)
    return True

'''====================================================
函数名:makenameForAddr
用  途:给指定模块函数重命名
备  注:
====================================================='''
def makenameForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeName(soAddr + offset, comm)
    else :
        print 'makenameForAddr fail'
    return True

'''====================================================
函数名:makeCommForAddr
用  途:给指定模块地址下注释
备  注:
====================================================='''
def makeCommForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeComm(soAddr + offset, comm)
    else :
        print 'makeCommForAddr fail'
    return True


'''====================================================
函数名:dumpMem
用  途:dump 指定大小的内存数据
备  注:
====================================================='''
def dumpMem(start, l, target):
    block = 1024
    c = l / block
    left = l % block
    fd = open(target, 'wb')
    if c > 0:
        for i in range(c):
            rawdex = idaapi.dbg_read_memory(start, block)
            fd.write(rawdex)
            start += block

    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        print rawdex == True
        fd.write(rawdex)
    fd.close()

'''====================================================
函数名:doDump
用  途:通过窗口dump内存数据
备  注:
====================================================='''
def doDump():
    start = AskAddr(0, 'Input Addr start in hex: ')
    print('start is ' + str(hex(start)))

    end = AskAddr(0, 'Input Addr end in hex: ')
    print('end is ' + str(hex(end)))

    l = end - start
    target = AskStr('./dump.mem', 'Input the dump file path')

    if l > 0 and start > 0x0 and target and AskYN(1, 'start is 0x%0x, len is %d, dump to %s' % (start, l, target)) == 1:
        dumpMem(start, l, target)
        print('Dump Finish')

'''====================================================
函数名:readIntFromMemory
用  途:从内存中读取一个int
备  注:
====================================================='''
def readIntFromMemory(addr):
    flag=0
    temp = addr
    temp1= temp
    if  temp%2:
        temp1= temp-1
        flag=1
    else:
        temp1=temp
    m4=dbg_read_memory(temp1, 4+flag)
    return  struct.unpack('i', m4)[0+flag]

'''====================================================
函数名:dbg_read_every_memory
用  途:从内存中读取一个int
备  注:优化过的
====================================================='''
def dbg_read_every_memory(start, len):

    tempStart=start - (start%0x1000)
    maxLen = (start%0x1000) + len
    #print maxLen
    #print tempStart
    rawdex = idaapi.dbg_read_memory(tempStart, maxLen)
    #print rawdex
    left = start%0x1000
    #print left
    #print rawdex[left:maxLen]
    return bytearray(rawdex[left:maxLen])

'''====================================================
函数名:readShortFromMemory
用  途:从内存中读取一个short
备  注:
====================================================='''
def readShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('h', m2)[0]

'''====================================================
函数名:readCharFromMemory
用  途:从内存中读取一个char
备  注:
====================================================='''
def readCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('c', m2)[0]

'''====================================================
函数名:readUIntFromMemory
用  途:从内存中读取一个uint
备  注:
====================================================='''
def readUIntFromMemory(addr):
    m4=dbg_read_memory(addr, 4)
    return  struct.unpack('I', m4)[0]

'''====================================================
函数名:readUShortFromMemory
用  途:从内存中读取一个ushort
备  注:
====================================================='''
def readUShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('H', m2)[0]

'''====================================================
函数名:readUCharFromMemory
用  途:从内存中读取一个uchar
备  注:
====================================================='''
def readUCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('C', m1)[0]

'''====================================================
函数名:copyMem
用  途:拷贝内存到另外一个区域r
备  注:
====================================================='''
def copyMem(start, l, target):
    addrTemp = target
    print 'copy start'
    block = 1024
    c = l / block
    left = l % block
    if c > 0:
        for i in range(c):
            print str(hex(start))
            print str(hex(addrTemp))
            rawdex = idaapi.dbg_read_memory(start, block)
            dbg_write_memory(addrTemp, rawdex)
            refresh_debugger_memory()
            start += block
            addrTemp += block

    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        dbg_write_memory(addrTemp, rawdex)
        refresh_debugger_memory()
    print 'copy end'


'''====================================================
函数名:FindData
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindData(addr, target):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            a = a + segStart
            break;
        segStart = segStart+512
    return a

'''====================================================
函数名:FindDataEx
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindDataEx(addr, target,offset, target2):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            rawdex2 = dbg_read_every_memory(segStart+a+offset, 512)
            b = rawdex2.find(target2)
            if b == 0:
                a = a + segStart
                break;
        segStart = segStart+512
    return a

#set debug breakpoint


'''-------------------------------------------------------------
#################start#######################
-------------------------------------------------------------'''
print 'by pass anti debug'
libBase = GetLibAddr('kernel32.dll')
print 'KernelBase addr = ' + str(hex(libBase))
addr = libBase + 0x163E0
print 'kernel32_SetThreadContext addr = ' + str(hex(addr))
write_dbg_memory(addr, "\xc2\x08\x00")
addr = libBase + 0x14030
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))
write_dbg_memory(addr, "\x33\xc0\xc2\x08\x00")
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))

AddBpt(0x4B8EBF)
SetBptAttr(0x4B8EBF, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)

write_dbg_memory(0x004B9788, changecode)
'''-------------------------------------------------------------
执行so 初始化函数开始时的处理
-------------------------------------------------------------'''
pcValue=GetRegValue('eip')
libBase=GetLibAddr('linker')
if pcValue == 0x4B8EBF:
    print 'bypass memory check'
    write_dbg_memory(0x004BC080, "\xBD\xA3\x9C\x10\x46\xF3\x2C\x00")

#coding=utf-8

import struct
from idaapi import *
from idc import *
from idautils import *

'''====================================================
函数名:GetLibAddr
用  途:根据模块名获得模块起始地址
备  注:此函数在SHT被破坏时将不起作用
====================================================='''
def GetLibAddr(targetName):
    targetBase = 0
    for i in Modules():
        #print i.name
        if targetName in i.name:
            targetBase = int("%x"%(i.base), 16)
            #print 'targetName:=' + targetName + 'targetBase:=' + str(targetBase)
            break
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False

    return targetBase

'''====================================================
函数名:GetSegAddrByName
用  途:根据段名获得段的起始地址
备  注:
====================================================='''
def GetSegAddrByName(targetName):
    tempAddr = FirstSeg()
    while tempAddr!=0:
        if tempAddr == 0:
            break
        name = SegName(tempAddr)
        if targetName in name:
            return tempAddr
        tempAddr = NextSeg(tempAddr)
    return 0

'''====================================================
函数名:writeMemoryForAddr
用  途:向模块地址写入指定shellcode
备  注:
====================================================='''
def writeMemoryForAddr(targetName, offset, buf):
    targetBase = 0
    targetBase = GetSegAddrByName(targetName)
    if targetBase == 0:
        #print 'targetBase None!!!'
        return False

    addr = targetBase + offset
    if not dbg_write_memory(addr, buf):
        return False

    refresh_debugger_memory()
    return True

'''====================================================
函数名:addBptForAddr
用  途:给模块指定偏移下断点
备  注:
====================================================='''
def addBptForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        SetBptAttr(soAddr + offset, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
        MakeComm(soAddr + offset, comm)
    else :
        print 'create point fail'
    return True

'''====================================================
函数名:DelBptForAddr
用  途:删除模块指定偏移的断点
备  注:
====================================================='''
def DelBptForAddr(targetName, offset):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        AddBpt(soAddr + offset)
        DelBpt(soAddr + offset)
    return True

'''====================================================
函数名:makenameForAddr
用  途:给指定模块函数重命名
备  注:
====================================================='''
def makenameForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeName(soAddr + offset, comm)
    else :
        print 'makenameForAddr fail'
    return True

'''====================================================
函数名:makeCommForAddr
用  途:给指定模块地址下注释
备  注:
====================================================='''
def makeCommForAddr(targetName, offset, comm):
    soAddr = GetSegAddrByName(targetName)
    if soAddr > 0 :
        MakeComm(soAddr + offset, comm)
    else :
        print 'makeCommForAddr fail'
    return True


'''====================================================
函数名:dumpMem
用  途:dump 指定大小的内存数据
备  注:
====================================================='''
def dumpMem(start, l, target):
    block = 1024
    c = l / block
    left = l % block
    fd = open(target, 'wb')
    if c > 0:
        for i in range(c):
            rawdex = idaapi.dbg_read_memory(start, block)
            fd.write(rawdex)
            start += block

    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        print rawdex == True
        fd.write(rawdex)
    fd.close()

'''====================================================
函数名:doDump
用  途:通过窗口dump内存数据
备  注:
====================================================='''
def doDump():
    start = AskAddr(0, 'Input Addr start in hex: ')
    print('start is ' + str(hex(start)))

    end = AskAddr(0, 'Input Addr end in hex: ')
    print('end is ' + str(hex(end)))

    l = end - start
    target = AskStr('./dump.mem', 'Input the dump file path')

    if l > 0 and start > 0x0 and target and AskYN(1, 'start is 0x%0x, len is %d, dump to %s' % (start, l, target)) == 1:
        dumpMem(start, l, target)
        print('Dump Finish')

'''====================================================
函数名:readIntFromMemory
用  途:从内存中读取一个int
备  注:
====================================================='''
def readIntFromMemory(addr):
    flag=0
    temp = addr
    temp1= temp
    if  temp%2:
        temp1= temp-1
        flag=1
    else:
        temp1=temp
    m4=dbg_read_memory(temp1, 4+flag)
    return  struct.unpack('i', m4)[0+flag]

'''====================================================
函数名:dbg_read_every_memory
用  途:从内存中读取一个int
备  注:优化过的
====================================================='''
def dbg_read_every_memory(start, len):

    tempStart=start - (start%0x1000)
    maxLen = (start%0x1000) + len
    #print maxLen
    #print tempStart
    rawdex = idaapi.dbg_read_memory(tempStart, maxLen)
    #print rawdex
    left = start%0x1000
    #print left
    #print rawdex[left:maxLen]
    return bytearray(rawdex[left:maxLen])

'''====================================================
函数名:readShortFromMemory
用  途:从内存中读取一个short
备  注:
====================================================='''
def readShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('h', m2)[0]

'''====================================================
函数名:readCharFromMemory
用  途:从内存中读取一个char
备  注:
====================================================='''
def readCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('c', m2)[0]

'''====================================================
函数名:readUIntFromMemory
用  途:从内存中读取一个uint
备  注:
====================================================='''
def readUIntFromMemory(addr):
    m4=dbg_read_memory(addr, 4)
    return  struct.unpack('I', m4)[0]

'''====================================================
函数名:readUShortFromMemory
用  途:从内存中读取一个ushort
备  注:
====================================================='''
def readUShortFromMemory(addr):
    m2=dbg_read_memory(addr, 2)
    return  struct.unpack('H', m2)[0]

'''====================================================
函数名:readUCharFromMemory
用  途:从内存中读取一个uchar
备  注:
====================================================='''
def readUCharFromMemory(addr):
    m1=dbg_read_memory(addr, 1)
    return  struct.unpack('C', m1)[0]

'''====================================================
函数名:copyMem
用  途:拷贝内存到另外一个区域r
备  注:
====================================================='''
def copyMem(start, l, target):
    addrTemp = target
    print 'copy start'
    block = 1024
    c = l / block
    left = l % block
    if c > 0:
        for i in range(c):
            print str(hex(start))
            print str(hex(addrTemp))
            rawdex = idaapi.dbg_read_memory(start, block)
            dbg_write_memory(addrTemp, rawdex)
            refresh_debugger_memory()
            start += block
            addrTemp += block

    if left > 0:
        rawdex = idaapi.dbg_read_memory(start, left)
        dbg_write_memory(addrTemp, rawdex)
        refresh_debugger_memory()
    print 'copy end'


'''====================================================
函数名:FindData
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindData(addr, target):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            a = a + segStart
            break;
        segStart = segStart+512
    return a

'''====================================================
函数名:FindDataEx
用  途:从指定位置查找指定字节的数据
备  注:返回第一个找到的位置
====================================================='''
def FindDataEx(addr, target,offset, target2):
    a = -1
    segStart = SegStart(addr)
    segEnd = SegEnd(addr)
    len=segEnd-segStart
    for i in range(len):
        rawdex1 = idaapi.dbg_read_memory(segStart, 1024)
        a = rawdex1.find(target)
        if a>= 0:
            rawdex2 = dbg_read_every_memory(segStart+a+offset, 512)
            b = rawdex2.find(target2)
            if b == 0:
                a = a + segStart
                break;
        segStart = segStart+512
    return a

#set debug breakpoint


'''-------------------------------------------------------------
#################start#######################
-------------------------------------------------------------'''
print 'by pass anti debug'
libBase = GetLibAddr('kernel32.dll')
print 'KernelBase addr = ' + str(hex(libBase))
addr = libBase + 0x163E0
print 'kernel32_SetThreadContext addr = ' + str(hex(addr))
write_dbg_memory(addr, "\xc2\x08\x00")
addr = libBase + 0x14030
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))
write_dbg_memory(addr, "\x33\xc0\xc2\x08\x00")
print 'kernel32_CheckRemoteDebuggerPresent addr = ' + str(hex(addr))

AddBpt(0x4B8EBF)
SetBptAttr(0x4B8EBF, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)

write_dbg_memory(0x004B9788, changecode)
'''-------------------------------------------------------------
执行so 初始化函数开始时的处理
-------------------------------------------------------------'''
pcValue=GetRegValue('eip')
libBase=GetLibAddr('linker')
if pcValue == 0x4B8EBF:
    print 'bypass memory check'
    write_dbg_memory(0x004BC080, "\xBD\xA3\x9C\x10\x46\xF3\x2C\x00")

三、去掉反调试
1、40299C函数
    将设置DRX硬件断点为401000、401001、401002、401003,感觉可以不用管,但是先用脚本让SetThreadContext函数直接返回。
signed int __usercall ChangeKeyAndAntiDebug@<eax>(int a1@<edx>, int a2@<ecx>, char a3@<bl>, int a4@<esi>, int a5)
{
  int v5; // eax
  int v6; // ebx
  int v7; // esi
  int v9; // [esp+14h] [ebp-2E4h]
  int v10; // [esp+18h] [ebp-2E0h]
  int v11; // [esp+1Ch] [ebp-2DCh]
  int v12; // [esp+20h] [ebp-2D8h]
  int v13; // [esp+24h] [ebp-2D4h]
  int v14; // [esp+2Ch] [ebp-2CCh]

  v5 = ChangeKeyByAddr(a1, a2, a4, sub_4025D3, 240);
  *(_BYTE *)(v5 + 82) &= a3;
  v6 = a5 + GetModuleHandleA(0);
  v9 = 65552;
  v7 = GetCurrentThread();
  GetThreadContext(v7, &v9);
  v10 = v6;
  v11 = v6 + 1;
  v13 = v6 + 3;
  v12 = v6 + 2;
  v14 |= 0x11110055u;
  SetThreadContext(v7, &v9);
  return 1;
}
2、反调试函数执行talbe.
main函数计算key的过程中,在某个时间点会调用如下9个反函数数组:
.data:004BC020 D3 25 40 00                         off_4BC020      dd offset sub_4025D3    ; DATA XREF: _main+5A4↑r
.data:004BC024 19 26 40 00                                         dd offset sub_402619
.data:004BC028 75 26 40 00                                         dd offset sub_402675
.data:004BC02C 22 27 40 00                                         dd offset sub_402722
.data:004BC030 6B 27 40 00                                         dd offset sub_40276B
.data:004BC034 66 25 40 00                                         dd offset sub_402566
.data:004BC038 D1 26 40 00                                         dd offset sub_4026D1
.data:004BC03C BC 27 40 00                                         dd offset sub_4027BC
main的如下位置调用上述函数
.text:004B9382 8B 85 44 D4 FF FF                                               mov     eax, [ebp-2BBCh]
.text:004B9388 8B 80 20 C0 4B 00                                               mov     eax, dword_4BC020[eax]
.text:004B938E C7 85 58 D4 FF FF 04 00 00 00                                   mov     dword ptr [ebp-2BA8h], 4
.text:004B9398 FF D0                                                           call    eax
.text:004B939A 83 F8 01                                                        cmp     eax, 1
.text:004B939D 83 95 48 D4 FF FF 00                                            adc     dword ptr [ebp-2BB8h], 0
.text:004B93A4 83 85 44 D4 FF FF 04                                            add     dword ptr [ebp-2BBCh], 4
如果返回结果为0,则累加计数器,只有非在调试器状态下,累加的结果为9,才可以使key计算正确。同时:
signed int __usercall ChangeKeyAndAntiDebug@<eax>(int a1@<edx>, int a2@<ecx>, char a3@<bl>, int a4@<esi>, int a5)
{
  int v5; // eax
  int v6; // ebx
  int v7; // esi
  int v9; // [esp+14h] [ebp-2E4h]
  int v10; // [esp+18h] [ebp-2E0h]
  int v11; // [esp+1Ch] [ebp-2DCh]
  int v12; // [esp+20h] [ebp-2D8h]
  int v13; // [esp+24h] [ebp-2D4h]
  int v14; // [esp+2Ch] [ebp-2CCh]

  v5 = ChangeKeyByAddr(a1, a2, a4, sub_4025D3, 240);
  *(_BYTE *)(v5 + 82) &= a3;
  v6 = a5 + GetModuleHandleA(0);
  v9 = 65552;
  v7 = GetCurrentThread();
  GetThreadContext(v7, &v9);
  v10 = v6;
  v11 = v6 + 1;
  v13 = v6 + 3;
  v12 = v6 + 2;
  v14 |= 0x11110055u;
  SetThreadContext(v7, &v9);
  return 1;
}
2、反调试函数执行talbe.
main函数计算key的过程中,在某个时间点会调用如下9个反函数数组:
.data:004BC020 D3 25 40 00                         off_4BC020      dd offset sub_4025D3    ; DATA XREF: _main+5A4↑r
.data:004BC024 19 26 40 00                                         dd offset sub_402619
.data:004BC028 75 26 40 00                                         dd offset sub_402675
.data:004BC02C 22 27 40 00                                         dd offset sub_402722
.data:004BC030 6B 27 40 00                                         dd offset sub_40276B
.data:004BC034 66 25 40 00                                         dd offset sub_402566
.data:004BC038 D1 26 40 00                                         dd offset sub_4026D1
.data:004BC03C BC 27 40 00                                         dd offset sub_4027BC
main的如下位置调用上述函数
.data:004BC020 D3 25 40 00                         off_4BC020      dd offset sub_4025D3    ; DATA XREF: _main+5A4↑r
.data:004BC024 19 26 40 00                                         dd offset sub_402619
.data:004BC028 75 26 40 00                                         dd offset sub_402675
.data:004BC02C 22 27 40 00                                         dd offset sub_402722
.data:004BC030 6B 27 40 00                                         dd offset sub_40276B
.data:004BC034 66 25 40 00                                         dd offset sub_402566
.data:004BC038 D1 26 40 00                                         dd offset sub_4026D1
.data:004BC03C BC 27 40 00                                         dd offset sub_4027BC
main的如下位置调用上述函数
.text:004B9382 8B 85 44 D4 FF FF                                               mov     eax, [ebp-2BBCh]
.text:004B9388 8B 80 20 C0 4B 00                                               mov     eax, dword_4BC020[eax]
.text:004B938E C7 85 58 D4 FF FF 04 00 00 00                                   mov     dword ptr [ebp-2BA8h], 4
.text:004B9398 FF D0                                                           call    eax
.text:004B939A 83 F8 01                                                        cmp     eax, 1
.text:004B939D 83 95 48 D4 FF FF 00                                            adc     dword ptr [ebp-2BB8h], 0
.text:004B93A4 83 85 44 D4 FF FF 04                                            add     dword ptr [ebp-2BBCh], 4
如果返回结果为0,则累加计数器,只有非在调试器状态下,累加的结果为9,才可以使key计算正确。同时:
.text:004B9382 8B 85 44 D4 FF FF                                               mov     eax, [ebp-2BBCh]
.text:004B9388 8B 80 20 C0 4B 00                                               mov     eax, dword_4BC020[eax]
.text:004B938E C7 85 58 D4 FF FF 04 00 00 00                                   mov     dword ptr [ebp-2BA8h], 4
.text:004B9398 FF D0                                                           call    eax
.text:004B939A 83 F8 01                                                        cmp     eax, 1
.text:004B939D 83 95 48 D4 FF FF 00                                            adc     dword ptr [ebp-2BB8h], 0
.text:004B93A4 83 85 44 D4 FF FF 04                                            add     dword ptr [ebp-2BBCh], 4
如果返回结果为0,则累加计数器,只有非在调试器状态下,累加的结果为9,才可以使key计算正确。同时:
 1)在函数sub_4025D3中对401F58进行计算checksum;
 1)在函数sub_4025D3中对401F58进行计算checksum;
 2)  sub_4028B3设置了异常处理程序;
nt __usercall sub_4025D3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>)
{
  int v3; // edx
  unsigned __int8 v4; // cf
  unsigned int v5; // ST00_4
  int v6; // eax
  int v8; // [esp+1Ch] [ebp-Ch]

  ChangeKeyByAddr(a1, a2, a3, ChangeKeyByAddr, 104);
  JUMPOUT(!(v4 | (v3 == -1)), (char *)&loc_402624 + 6);
  __writeeflags(v5);
  v6 = GetCurrentProcess();
  CheckRemoteDebuggerPresent(v6, (char *)&v8 + 1);
  return *(int *)((char *)&v8 + 1);
}

signed int sub_4028B3()
{
  signed int v1; // [esp+18h] [ebp-10h]
  int v2; // [esp+1Ch] [ebp-Ch]

  v2 = 0;
  v1 = 0;
  if ( !setjmp3(Buf, 0) )
  {
    __debugbreak();
    v2 = SetUnhandledExceptionFilter(sub_40254C);
    v1 = 1;
  }
  SetUnhandledExceptionFilter(v2);
  return v1;
}
 在前面去混淆的时候直接让call eax,变为xor eax,eax,不去调用9个反调试函数,并能够使返回结果累加为9。(可能会使后面的计算key有误,先暂时这样处理)
至此准备工作做完,开始进行分析。
三、main 函数
去掉混淆后main函数如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ebp
  int cur1; // edi
  int v6; // esi
  void *v7; // esp
  int v8; // edx
  int v9; // ecx
  int v10; // edx
  int v11; // ecx
  int v12; // ecx
  int v13; // eax
  int i; // edx
  int v15; // eax
  char *v16; // ebx
  unsigned __int8 *dataSN; // esi
  unsigned __int8 *dataSnEnd; // edx
  char v19; // t2
  char v20; // ah
  int v21; // eax
  int num; // eax
  int *tempBuf; // eax
  int *malocBufEnd; // edx
  int *keyVectorBuf; // ebx
  int k; // eax
  int curIndex1; // ebx
  int muti9_Value; // ebx
  int *tempBuf1; // eax
  int i1; // edx
  int v31; // ebx
  int *pmalloc2Buf; // edx
  int *v33; // eax
  int v34; // ecx
  signed int nextKeyValue; // eax
  int v36; // edx
  int v37; // et1
  int *v38; // ebx
  int cnt_9; // edi
  __int64 m3; // rax
  signed __int64 v41; // rt2
  __int64 m1; // rax
  signed __int64 leftValue; // rt2
  int keyValue1; // edi
  char v45; // al
  int v46; // ebx
  int v47; // eax
  signed int v48; // eax
  int v49; // edx
  char *v50; // ecx
  int v51; // eax
  int v52; // ebx
  bool v53; // zf
  _DWORD *v54; // eax
  int curIndex2; // [esp+0h] [ebp-2C0Ch]
  int sn_value; // [esp+4h] [ebp-2C08h]
  int *dataSn; // [esp+18h] [ebp-2BF4h]
  int max; // [esp+1Ch] [ebp-2BF0h]
  int v60; // [esp+20h] [ebp-2BECh]
  int m_Index; // [esp+24h] [ebp-2BE8h]
  int v62; // [esp+28h] [ebp-2BE4h]
  int index; // [esp+2Ch] [ebp-2BE0h]
  int stepIndex; // [esp+30h] [ebp-2BDCh]
  int v65; // [esp+34h] [ebp-2BD8h]
  int curIndex; // [esp+38h] [ebp-2BD4h]
  int keyValue; // [esp+3Ch] [ebp-2BD0h]
  int m; // [esp+40h] [ebp-2BCCh]
  int m2; // [esp+44h] [ebp-2BC8h]
  int snLen; // [esp+48h] [ebp-2BC4h]
  int v71; // [esp+4Ch] [ebp-2BC0h]
  int step; // [esp+50h] [ebp-2BBCh]
  char *(__cdecl *v73)(int, int, __int64, _BYTE *, int); // [esp+64h] [ebp-2BA8h]
  int *v74; // [esp+68h] [ebp-2BA4h]
  int *v75; // [esp+6Ch] [ebp-2BA0h]
  void *v76; // [esp+70h] [ebp-2B9Ch]
  int *v77; // [esp+74h] [ebp-2B98h]
  struct vector lastKeyTable; // [esp+80h] [ebp-2B8Ch]
  struct vector v79; // [esp+8Ch] [ebp-2B80h]
  struct vector keyVector; // [esp+98h] [ebp-2B74h]
  struct vector temKeyValueVetor; // [esp+A4h] [ebp-2B68h]
  int inputSn; // [esp+C0h] [ebp-2B4Ch]
  unsigned __int8 v83; // [esp+1C0h] [ebp-2A4Ch]
  int v84; // [esp+2C0h] [ebp-294Ch]
  struct DataTable newKeyTable; // [esp+3C0h] [ebp-284Ch]
  struct DataTable key2Table; // [esp+17D0h] [ebp-143Ch]
  int v87; // [esp+2BE0h] [ebp-2Ch]
  int *v88; // [esp+2BE8h] [ebp-24h]
  int v89; // [esp+2BECh] [ebp-20h]
  int v90; // [esp+2BF0h] [ebp-1Ch]
  int v91; // [esp+2BF4h] [ebp-18h]
  int v92; // [esp+2BF8h] [ebp-14h]
  int v93; // [esp+2BFCh] [ebp-10h]
  int retaddr; // [esp+2C0Ch] [ebp+0h]

  v93 = retaddr;
  v92 = v4;
  v91 = cur1;
  v90 = v6;
  v89 = v3;
  v88 = &argc;
  v7 = alloca(11240);
  v73 = sub_4B85B0;
  v74 = dword_4B9D1C;
  v76 = &loc_4B9827;
  v75 = &v87;
  v77 = &curIndex2;
  sub_40D9D0(&v71);
  sub_40C510();
  ChangeKeyByAddr(v8, v9, v6, 0, 0x25A);
  step = -1;
  ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
  create0x400Random(&newKeyTable);
  step = 1;
  create0x400Random(&key2Table);
  step = 2;
  sub_4B5240((int)&stdio, &inputSn);
  for ( snLen = 0; ; ++snLen )
  {
    v13 = snLen;
    if ( !*((_BYTE *)&v92 + snLen - 0x2B38) )
      break;
  }
  i = 0;
  LOBYTE(v3) = 0x37;
  while ( i != snLen )
  {
    LOBYTE(v13) = *((_BYTE *)&v92 + i - 0x2B38);// sn
    LOBYTE(v12) = '0';
    if ( (char)v13 > '9' )
    {
      LOBYTE(v12) = '=';
      if ( (char)v13 < 'a' )
        v12 = v3;
    }
    v15 = v13 - v12;
    *((_BYTE *)&v92 + i - 0x2A38) = v15;        // data_sn
    v13 = v15 - 1;
    if ( (unsigned __int8)v13 > 0xEu )
      goto LABEL_61;
    ++i;
  }
  v16 = (char *)&v84;
  dataSN = &v83;
  *((_BYTE *)&v92 + snLen - 0x2A38) = 0;
  while ( snLen )
  {
    dataSnEnd = &v83 + snLen;
    do
    {
      v19 = *dataSnEnd % 0xAu;
      *dataSnEnd /= 0xAu;
      *(dataSnEnd-- - 1) += 16 * v19;
    }
    while ( &v83 != dataSnEnd );
    v20 = v83 % 0xAu;
    v83 /= 0xAu;
    *v16 = v20;                                 // 余数
    do
    {
      cur1 = snLen;
      v21 = snLen - 1;
      if ( *(&v83 + snLen - 1) )
        break;
      --snLen;
    }                                           // ((c0*0X0a+c1)*0x0a + c2) ....
    while ( v21 );
    ++v16;
  }
  step = 2;
  SetTableAndDiv0x0A(&newKeyTable, &source, 0x10);
  sn_value = SetTableAndDiv0x0A(&key2Table, &byte_4BC088, 16);
  table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);
  curIndex2 = cur1;
  CallTableDiv(&newKeyTable);                   // 转换成new constKeyTable 
  lastKeyTable.start = 0;
  lastKeyTable.last = 0;
  lastKeyTable.end = 0;
  v62 = 0;
  v65 = 0;
  index = 0;
  m = 0;
  while ( 1 )
  {
    step = 3;
    num = GetTableNum(&newKeyTable);
    if ( index >= num )
      break;
    keyValue = GetTableValueByIndex(&newKeyTable, index);
    keyVector.start = 0;
    keyVector.last = 0;
    keyVector.end = 0;
    tempBuf = (int *)malloc_0(0x510);
    malocBufEnd = tempBuf + 0x144;
    keyVectorBuf = tempBuf;
    keyVector.start = tempBuf;
    k = 0;
    keyVector.end = malocBufEnd;
    do
    {
      keyVectorBuf[k] = 0;                      // clear buf
      ++k;
    }
    while ( k != 0x144 );
    keyVector.last = malocBufEnd;
    if ( keyValue )
    {
      if ( keyValue <= 9 )
      {
        m1 = m;
        keyVectorBuf[(_DWORD)m1] = 1;
        leftValue = m1 % 9;
        keyValue1 = keyValue;
        keyVectorBuf[keyValue + 9 * (unsigned int)(m1 / 9) + 0x50] = 1;
        LODWORD(m1) = keyValue1 + 9 * (unsigned __int64)(m1 % 9) + 0xA1;
        cur1 = 3;
        keyVectorBuf[(_DWORD)m1] = 1;
        dataSN = (unsigned __int8 *)keyValue;
        keyVectorBuf[keyValue + 9 * (3 * (m / 27) + (signed int)leftValue / 3) + 0xF2] = 1;
        step = 4;
        Vector_push(&lastKeyTable, &keyVector);
        stepIndex = v65 + 1;
        sn_value = SetTableValueByIndex(&g_snTable, v65, keyValue);// 对于constKey 小于等于9 插入到g_snTable中,大于不放
        curIndex2 = sn_value;
        ++m;
      }
      else
      {
        curIndex = 0;
        dataSn = (int *)((char *)&v92 + v62 - 0x2938);// 获取SN指针
        while ( 1 )
        {
          m_Index = curIndex + v62;
          stepIndex = curIndex + v65;
          m2 = curIndex + m;
          if ( curIndex >= keyValue - 9 )
            break;
          curIndex1 = curIndex;
          sn_value = *((unsigned __int8 *)dataSn + curIndex);// 取出SN
          step = 4;
          SetTableValueByIndex(&g_snTable, stepIndex, sn_value);
          sn_value = curIndex1;
          curIndex2 = curIndex1;
          m_Index = 4 * m2;
          muti9_Value = 9 * (m2 / 9);
          stepIndex = 36 * (m2 / 9) + 0x144;
          max = 36 * (m2 / 9) + 0x168;
          v60 = 4 * (9 * (m2 % 9) - muti9_Value);
          m2 = 4 * (9 * (m2 % 9 / 3 + 3 * (m2 / 27)) - muti9_Value);
          do
          {
            temKeyValueVetor.start = 0;
            temKeyValueVetor.last = 0;
            temKeyValueVetor.end = 0;
            step = 4;
            tempBuf1 = (int *)malloc_0(0x510);
            temKeyValueVetor.start = tempBuf1;
            i1 = 0;
            temKeyValueVetor.end = tempBuf1 + 0x144;
            do
            {
              tempBuf1[i1] = 0;
              ++i1;
            }
            while ( i1 != 0x144 );
            cur1 = stepIndex;
            v31 = v60;
            temKeyValueVetor.last = tempBuf1 + 0x144;
            *(int *)((char *)tempBuf1 + m_Index) = 1;// 0
            *(int *)((char *)tempBuf1 + cur1) = 1;// 51
            pmalloc2Buf = (int *)((char *)tempBuf1 + v31);
            v33 = (int *)((char *)tempBuf1 + m2);
            *(int *)((char *)pmalloc2Buf + cur1 + 0x144) = 1;// A1
            *(int *)((char *)v33 + cur1 + 0x288) = 1;// F2
            step = 5;
            Vector_push(&lastKeyTable, &temKeyValueVetor);
            curIndex2 = v34;
            free_0((int *)&temKeyValueVetor);
            stepIndex += 4;
            dataSN = (unsigned __int8 *)stepIndex;
          }
          while ( max != stepIndex );
          ++curIndex;
        }
        step = 4;
        nextKeyValue = GetTableValueByIndex(&newKeyTable, index + 1);
        curIndex2 = v36;
        if ( nextKeyValue <= 9 )
        {
          v62 = m_Index;
          m = m2;
        }
        else
        {
          m = 0;
          keyValue = 0;
          do
          {
            v37 = *(int *)((char *)&off_4BC020 + keyValue);
            step = 4;
            ++m;                                // 应该等于9
            keyValue += 4;
          }
          while ( keyValue != 0x24 );
          v38 = keyVector.start;
          cnt_9 = m;
          m3 = m2;
          keyVector.start[m3] = 1;
          v41 = m3 % 9;
          v38[cnt_9 + 9 * (unsigned int)(m3 / 9) + 0x50] = 1;
          LODWORD(m3) = cnt_9 + 9 * (unsigned __int64)(m3 % 9) + 0xA1;
          cur1 = 3;
          v38[(_DWORD)m3] = 1;
          dataSN = (unsigned __int8 *)m;
          v38[m + 9 * (3 * (m2 / 27) + (signed int)v41 / 3) + 0xF2] = 1;
          step = 4;
          curIndex2 = (int)Vector_push(&lastKeyTable, &keyVector);
          m = m2 + 1;
          v62 = m_Index;
        }
      }
    }
    else
    {
      stepIndex = v65;
    }
    free_0((int *)&keyVector);
    ++index;
    v65 = stepIndex;
  }
  step = 3;
  sub_402BEE(
    &temKeyValueVetor,
    (int)&lastKeyTable,
    0xAAAAAAAB * ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2),
    0x144);
  step = 6;
  v45 = sub_402DB6(&temKeyValueVetor, 0);
  curIndex2 = cur1;
  if ( v45 )
  {
    step = 6;
    vectorCpy(&v79, (struct vector *)((char *)&temKeyValueVetor + 4));
    curIndex2 = (int)dataSN;
    m = 0;
    keyValue = 0;
    do
    {
      v46 = keyValue;
      curIndex2 = (int)&lastKeyTable.start[3 * (*(int *)((char *)v79.start + keyValue) - 1)];
      step = 8;
      vectorCpy(&keyVector, (struct vector *)curIndex2);
      curIndex2 = v46;
      m2 = 0;
      do
      {
        if ( keyVector.start[m2] == 1 )
          break;
        ++m2;
      }
      while ( m2 != 81 );
      if ( m2 == 0x28 )
      {
        --m;
      }
      else
      {
        m2 -= m2 >= 41;
        v47 = 0;
        do
        {
          if ( keyVector.start[v47 + 81] == 1 )
            break;
          ++v47;
        }
        while ( v47 != 81 );
        curIndex = v47 % 9 + 1;
        step = 7;
        GetTableValueByIndex(&g_snTable, m2);
        v65 = (int)off_4BC060;
        v48 = GetTableValueByIndex(&g_snTable, m2);
        curIndex2 = v49;
        m += curIndex == *(unsigned __int8 *)(v65 + v48);
      }
      free_0((int *)&keyVector);
      keyValue += 4;
    }
    while ( keyValue != 0x144 );
    v50 = off_4BC05C;
    v51 = 0;
    do
    {
      v52 = (unsigned __int8)v50[v51];
      snLen += 9 * (v52 ^ m) ^ 0x37;
      v53 = m == v52;
      v50[v51] = v52 ^ m;
      if ( v53 )
        break;
      ++v51;
    }
    while ( v51 != 0x201 );
    if ( snLen == 0x1F1A )                      // 成功
    {
      step = 8;
      v54 = (_DWORD *)sub_4B3F00((int)&dword_4BD9A0, off_4BC05C);// 输出
      sub_4B0DB0(v54);
    }
    free_0((int *)&v79);
  }
  j_free(temKeyValueVetor.start);
  free_0((int *)&temKeyValueVetor.last);
  sub_402966((int *)&lastKeyTable);
LABEL_61:
  nop();
  nop();
  sub_40DA40(&v71);
  return 0;
}
流程如下:
1、调用 40D9D0  40C510 进行初始化变量同时初始化g_snTable(4C8020)用于最后校验的一个表,里面包含输入sn信息。
2、进行如下调用,
nt __usercall sub_4025D3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>)
{
  int v3; // edx
  unsigned __int8 v4; // cf
  unsigned int v5; // ST00_4
  int v6; // eax
  int v8; // [esp+1Ch] [ebp-Ch]

  ChangeKeyByAddr(a1, a2, a3, ChangeKeyByAddr, 104);
  JUMPOUT(!(v4 | (v3 == -1)), (char *)&loc_402624 + 6);
  __writeeflags(v5);
  v6 = GetCurrentProcess();
  CheckRemoteDebuggerPresent(v6, (char *)&v8 + 1);
  return *(int *)((char *)&v8 + 1);
}

signed int sub_4028B3()
{
  signed int v1; // [esp+18h] [ebp-10h]
  int v2; // [esp+1Ch] [ebp-Ch]

  v2 = 0;
  v1 = 0;
  if ( !setjmp3(Buf, 0) )
  {
    __debugbreak();
    v2 = SetUnhandledExceptionFilter(sub_40254C);
    v1 = 1;
  }
  SetUnhandledExceptionFilter(v2);
  return v1;
}
 在前面去混淆的时候直接让call eax,变为xor eax,eax,不去调用9个反调试函数,并能够使返回结果累加为9。(可能会使后面的计算key有误,先暂时这样处理)
nt __usercall sub_4025D3@<eax>(int a1@<edx>, int a2@<ecx>, int a3@<esi>)
{
  int v3; // edx
  unsigned __int8 v4; // cf
  unsigned int v5; // ST00_4
  int v6; // eax
  int v8; // [esp+1Ch] [ebp-Ch]

  ChangeKeyByAddr(a1, a2, a3, ChangeKeyByAddr, 104);
  JUMPOUT(!(v4 | (v3 == -1)), (char *)&loc_402624 + 6);
  __writeeflags(v5);
  v6 = GetCurrentProcess();
  CheckRemoteDebuggerPresent(v6, (char *)&v8 + 1);
  return *(int *)((char *)&v8 + 1);
}

signed int sub_4028B3()
{
  signed int v1; // [esp+18h] [ebp-10h]
  int v2; // [esp+1Ch] [ebp-Ch]

  v2 = 0;
  v1 = 0;
  if ( !setjmp3(Buf, 0) )
  {
    __debugbreak();
    v2 = SetUnhandledExceptionFilter(sub_40254C);
    v1 = 1;
  }
  SetUnhandledExceptionFilter(v2);
  return v1;
}
 在前面去混淆的时候直接让call eax,变为xor eax,eax,不去调用9个反调试函数,并能够使返回结果累加为9。(可能会使后面的计算key有误,先暂时这样处理)
至此准备工作做完,开始进行分析。
三、main 函数
去掉混淆后main函数如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ebp
  int cur1; // edi
  int v6; // esi
  void *v7; // esp
  int v8; // edx
  int v9; // ecx
  int v10; // edx
  int v11; // ecx
  int v12; // ecx
  int v13; // eax
  int i; // edx
  int v15; // eax
  char *v16; // ebx
  unsigned __int8 *dataSN; // esi
  unsigned __int8 *dataSnEnd; // edx
  char v19; // t2
  char v20; // ah
  int v21; // eax
  int num; // eax
  int *tempBuf; // eax
  int *malocBufEnd; // edx
  int *keyVectorBuf; // ebx
  int k; // eax
  int curIndex1; // ebx
  int muti9_Value; // ebx
  int *tempBuf1; // eax
  int i1; // edx
  int v31; // ebx
  int *pmalloc2Buf; // edx
  int *v33; // eax
  int v34; // ecx
  signed int nextKeyValue; // eax
  int v36; // edx
  int v37; // et1
  int *v38; // ebx
  int cnt_9; // edi
  __int64 m3; // rax
  signed __int64 v41; // rt2
  __int64 m1; // rax
  signed __int64 leftValue; // rt2
  int keyValue1; // edi
  char v45; // al
  int v46; // ebx
  int v47; // eax
  signed int v48; // eax
  int v49; // edx
  char *v50; // ecx
  int v51; // eax
  int v52; // ebx
  bool v53; // zf
  _DWORD *v54; // eax
  int curIndex2; // [esp+0h] [ebp-2C0Ch]
  int sn_value; // [esp+4h] [ebp-2C08h]
  int *dataSn; // [esp+18h] [ebp-2BF4h]
  int max; // [esp+1Ch] [ebp-2BF0h]
  int v60; // [esp+20h] [ebp-2BECh]
  int m_Index; // [esp+24h] [ebp-2BE8h]
  int v62; // [esp+28h] [ebp-2BE4h]
  int index; // [esp+2Ch] [ebp-2BE0h]
  int stepIndex; // [esp+30h] [ebp-2BDCh]
  int v65; // [esp+34h] [ebp-2BD8h]
  int curIndex; // [esp+38h] [ebp-2BD4h]
  int keyValue; // [esp+3Ch] [ebp-2BD0h]
  int m; // [esp+40h] [ebp-2BCCh]
  int m2; // [esp+44h] [ebp-2BC8h]
  int snLen; // [esp+48h] [ebp-2BC4h]
  int v71; // [esp+4Ch] [ebp-2BC0h]
  int step; // [esp+50h] [ebp-2BBCh]
  char *(__cdecl *v73)(int, int, __int64, _BYTE *, int); // [esp+64h] [ebp-2BA8h]
  int *v74; // [esp+68h] [ebp-2BA4h]
  int *v75; // [esp+6Ch] [ebp-2BA0h]
  void *v76; // [esp+70h] [ebp-2B9Ch]
  int *v77; // [esp+74h] [ebp-2B98h]
  struct vector lastKeyTable; // [esp+80h] [ebp-2B8Ch]
  struct vector v79; // [esp+8Ch] [ebp-2B80h]
  struct vector keyVector; // [esp+98h] [ebp-2B74h]
  struct vector temKeyValueVetor; // [esp+A4h] [ebp-2B68h]
  int inputSn; // [esp+C0h] [ebp-2B4Ch]
  unsigned __int8 v83; // [esp+1C0h] [ebp-2A4Ch]
  int v84; // [esp+2C0h] [ebp-294Ch]
  struct DataTable newKeyTable; // [esp+3C0h] [ebp-284Ch]
  struct DataTable key2Table; // [esp+17D0h] [ebp-143Ch]
  int v87; // [esp+2BE0h] [ebp-2Ch]
  int *v88; // [esp+2BE8h] [ebp-24h]
  int v89; // [esp+2BECh] [ebp-20h]
  int v90; // [esp+2BF0h] [ebp-1Ch]
  int v91; // [esp+2BF4h] [ebp-18h]
  int v92; // [esp+2BF8h] [ebp-14h]
  int v93; // [esp+2BFCh] [ebp-10h]
  int retaddr; // [esp+2C0Ch] [ebp+0h]

  v93 = retaddr;
  v92 = v4;
  v91 = cur1;
  v90 = v6;
  v89 = v3;
  v88 = &argc;
  v7 = alloca(11240);
  v73 = sub_4B85B0;
  v74 = dword_4B9D1C;
  v76 = &loc_4B9827;
  v75 = &v87;
  v77 = &curIndex2;
  sub_40D9D0(&v71);
  sub_40C510();
  ChangeKeyByAddr(v8, v9, v6, 0, 0x25A);
  step = -1;
  ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
  create0x400Random(&newKeyTable);
  step = 1;
  create0x400Random(&key2Table);
  step = 2;
  sub_4B5240((int)&stdio, &inputSn);
  for ( snLen = 0; ; ++snLen )
  {
    v13 = snLen;
    if ( !*((_BYTE *)&v92 + snLen - 0x2B38) )
      break;
  }
  i = 0;
  LOBYTE(v3) = 0x37;
  while ( i != snLen )
  {
    LOBYTE(v13) = *((_BYTE *)&v92 + i - 0x2B38);// sn
    LOBYTE(v12) = '0';
    if ( (char)v13 > '9' )
    {
      LOBYTE(v12) = '=';
      if ( (char)v13 < 'a' )
        v12 = v3;
    }
    v15 = v13 - v12;
    *((_BYTE *)&v92 + i - 0x2A38) = v15;        // data_sn
    v13 = v15 - 1;
    if ( (unsigned __int8)v13 > 0xEu )
      goto LABEL_61;
    ++i;
  }
  v16 = (char *)&v84;
  dataSN = &v83;
  *((_BYTE *)&v92 + snLen - 0x2A38) = 0;
  while ( snLen )
  {
    dataSnEnd = &v83 + snLen;
    do
    {
      v19 = *dataSnEnd % 0xAu;
      *dataSnEnd /= 0xAu;
      *(dataSnEnd-- - 1) += 16 * v19;
    }
    while ( &v83 != dataSnEnd );
    v20 = v83 % 0xAu;
    v83 /= 0xAu;
    *v16 = v20;                                 // 余数
    do
    {
      cur1 = snLen;
      v21 = snLen - 1;
      if ( *(&v83 + snLen - 1) )
        break;
      --snLen;
    }                                           // ((c0*0X0a+c1)*0x0a + c2) ....
    while ( v21 );
    ++v16;
  }
  step = 2;
  SetTableAndDiv0x0A(&newKeyTable, &source, 0x10);
  sn_value = SetTableAndDiv0x0A(&key2Table, &byte_4BC088, 16);
  table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);
  curIndex2 = cur1;
  CallTableDiv(&newKeyTable);                   // 转换成new constKeyTable 
  lastKeyTable.start = 0;
  lastKeyTable.last = 0;
  lastKeyTable.end = 0;
  v62 = 0;
  v65 = 0;
  index = 0;
  m = 0;
  while ( 1 )
  {
    step = 3;
    num = GetTableNum(&newKeyTable);
    if ( index >= num )
      break;
    keyValue = GetTableValueByIndex(&newKeyTable, index);
    keyVector.start = 0;
    keyVector.last = 0;
    keyVector.end = 0;
    tempBuf = (int *)malloc_0(0x510);
    malocBufEnd = tempBuf + 0x144;
    keyVectorBuf = tempBuf;
    keyVector.start = tempBuf;
    k = 0;
    keyVector.end = malocBufEnd;
    do
    {
      keyVectorBuf[k] = 0;                      // clear buf
      ++k;
    }
    while ( k != 0x144 );
    keyVector.last = malocBufEnd;
    if ( keyValue )
    {
      if ( keyValue <= 9 )
      {
        m1 = m;
        keyVectorBuf[(_DWORD)m1] = 1;
        leftValue = m1 % 9;
        keyValue1 = keyValue;
        keyVectorBuf[keyValue + 9 * (unsigned int)(m1 / 9) + 0x50] = 1;
        LODWORD(m1) = keyValue1 + 9 * (unsigned __int64)(m1 % 9) + 0xA1;
        cur1 = 3;
        keyVectorBuf[(_DWORD)m1] = 1;
        dataSN = (unsigned __int8 *)keyValue;
        keyVectorBuf[keyValue + 9 * (3 * (m / 27) + (signed int)leftValue / 3) + 0xF2] = 1;
        step = 4;
        Vector_push(&lastKeyTable, &keyVector);
        stepIndex = v65 + 1;
        sn_value = SetTableValueByIndex(&g_snTable, v65, keyValue);// 对于constKey 小于等于9 插入到g_snTable中,大于不放
        curIndex2 = sn_value;
        ++m;
      }
      else
      {
        curIndex = 0;
        dataSn = (int *)((char *)&v92 + v62 - 0x2938);// 获取SN指针
        while ( 1 )
        {
          m_Index = curIndex + v62;
          stepIndex = curIndex + v65;
          m2 = curIndex + m;
          if ( curIndex >= keyValue - 9 )
            break;
          curIndex1 = curIndex;
          sn_value = *((unsigned __int8 *)dataSn + curIndex);// 取出SN
          step = 4;
          SetTableValueByIndex(&g_snTable, stepIndex, sn_value);
          sn_value = curIndex1;
          curIndex2 = curIndex1;
          m_Index = 4 * m2;
          muti9_Value = 9 * (m2 / 9);
          stepIndex = 36 * (m2 / 9) + 0x144;
          max = 36 * (m2 / 9) + 0x168;
          v60 = 4 * (9 * (m2 % 9) - muti9_Value);
          m2 = 4 * (9 * (m2 % 9 / 3 + 3 * (m2 / 27)) - muti9_Value);
          do
          {
            temKeyValueVetor.start = 0;
            temKeyValueVetor.last = 0;
            temKeyValueVetor.end = 0;
            step = 4;
            tempBuf1 = (int *)malloc_0(0x510);
            temKeyValueVetor.start = tempBuf1;
            i1 = 0;
            temKeyValueVetor.end = tempBuf1 + 0x144;
            do
            {
              tempBuf1[i1] = 0;
              ++i1;
            }
            while ( i1 != 0x144 );
            cur1 = stepIndex;
            v31 = v60;
            temKeyValueVetor.last = tempBuf1 + 0x144;
            *(int *)((char *)tempBuf1 + m_Index) = 1;// 0
            *(int *)((char *)tempBuf1 + cur1) = 1;// 51
            pmalloc2Buf = (int *)((char *)tempBuf1 + v31);
            v33 = (int *)((char *)tempBuf1 + m2);
            *(int *)((char *)pmalloc2Buf + cur1 + 0x144) = 1;// A1
            *(int *)((char *)v33 + cur1 + 0x288) = 1;// F2
            step = 5;
            Vector_push(&lastKeyTable, &temKeyValueVetor);
            curIndex2 = v34;
            free_0((int *)&temKeyValueVetor);
            stepIndex += 4;
            dataSN = (unsigned __int8 *)stepIndex;
          }
          while ( max != stepIndex );
          ++curIndex;
        }
        step = 4;
        nextKeyValue = GetTableValueByIndex(&newKeyTable, index + 1);
        curIndex2 = v36;
        if ( nextKeyValue <= 9 )
        {
          v62 = m_Index;
          m = m2;
        }
        else
        {
          m = 0;
          keyValue = 0;
          do
          {
            v37 = *(int *)((char *)&off_4BC020 + keyValue);
            step = 4;
            ++m;                                // 应该等于9
            keyValue += 4;
          }
          while ( keyValue != 0x24 );
          v38 = keyVector.start;
          cnt_9 = m;
          m3 = m2;
          keyVector.start[m3] = 1;
          v41 = m3 % 9;
          v38[cnt_9 + 9 * (unsigned int)(m3 / 9) + 0x50] = 1;
          LODWORD(m3) = cnt_9 + 9 * (unsigned __int64)(m3 % 9) + 0xA1;
          cur1 = 3;
          v38[(_DWORD)m3] = 1;
          dataSN = (unsigned __int8 *)m;
          v38[m + 9 * (3 * (m2 / 27) + (signed int)v41 / 3) + 0xF2] = 1;
          step = 4;
          curIndex2 = (int)Vector_push(&lastKeyTable, &keyVector);
          m = m2 + 1;
          v62 = m_Index;
        }
      }
    }
    else
    {
      stepIndex = v65;
    }
    free_0((int *)&keyVector);
    ++index;
    v65 = stepIndex;
  }
  step = 3;
  sub_402BEE(
    &temKeyValueVetor,
    (int)&lastKeyTable,
    0xAAAAAAAB * ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2),
    0x144);
  step = 6;
  v45 = sub_402DB6(&temKeyValueVetor, 0);
  curIndex2 = cur1;
  if ( v45 )
  {
    step = 6;
    vectorCpy(&v79, (struct vector *)((char *)&temKeyValueVetor + 4));
    curIndex2 = (int)dataSN;
    m = 0;
    keyValue = 0;
    do
    {
      v46 = keyValue;
      curIndex2 = (int)&lastKeyTable.start[3 * (*(int *)((char *)v79.start + keyValue) - 1)];
      step = 8;
      vectorCpy(&keyVector, (struct vector *)curIndex2);
      curIndex2 = v46;
      m2 = 0;
      do
      {
        if ( keyVector.start[m2] == 1 )
          break;
        ++m2;
      }
      while ( m2 != 81 );
      if ( m2 == 0x28 )
      {
        --m;
      }
      else
      {
        m2 -= m2 >= 41;
        v47 = 0;
        do
        {
          if ( keyVector.start[v47 + 81] == 1 )
            break;
          ++v47;
        }
        while ( v47 != 81 );
        curIndex = v47 % 9 + 1;
        step = 7;
        GetTableValueByIndex(&g_snTable, m2);
        v65 = (int)off_4BC060;
        v48 = GetTableValueByIndex(&g_snTable, m2);
        curIndex2 = v49;
        m += curIndex == *(unsigned __int8 *)(v65 + v48);
      }
      free_0((int *)&keyVector);
      keyValue += 4;
    }
    while ( keyValue != 0x144 );
    v50 = off_4BC05C;
    v51 = 0;
    do
    {
      v52 = (unsigned __int8)v50[v51];
      snLen += 9 * (v52 ^ m) ^ 0x37;
      v53 = m == v52;
      v50[v51] = v52 ^ m;
      if ( v53 )
        break;
      ++v51;
    }
    while ( v51 != 0x201 );
    if ( snLen == 0x1F1A )                      // 成功
    {
      step = 8;
      v54 = (_DWORD *)sub_4B3F00((int)&dword_4BD9A0, off_4BC05C);// 输出
      sub_4B0DB0(v54);
    }
    free_0((int *)&v79);
  }
  j_free(temKeyValueVetor.start);
  free_0((int *)&temKeyValueVetor.last);
  sub_402966((int *)&lastKeyTable);
LABEL_61:
  nop();
  nop();
  sub_40DA40(&v71);
  return 0;
}
流程如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ebp
  int cur1; // edi
  int v6; // esi
  void *v7; // esp
  int v8; // edx
  int v9; // ecx
  int v10; // edx
  int v11; // ecx
  int v12; // ecx
  int v13; // eax
  int i; // edx
  int v15; // eax
  char *v16; // ebx
  unsigned __int8 *dataSN; // esi
  unsigned __int8 *dataSnEnd; // edx
  char v19; // t2
  char v20; // ah
  int v21; // eax
  int num; // eax
  int *tempBuf; // eax
  int *malocBufEnd; // edx
  int *keyVectorBuf; // ebx
  int k; // eax
  int curIndex1; // ebx
  int muti9_Value; // ebx
  int *tempBuf1; // eax
  int i1; // edx
  int v31; // ebx
  int *pmalloc2Buf; // edx
  int *v33; // eax
  int v34; // ecx
  signed int nextKeyValue; // eax
  int v36; // edx
  int v37; // et1
  int *v38; // ebx
  int cnt_9; // edi
  __int64 m3; // rax
  signed __int64 v41; // rt2
  __int64 m1; // rax
  signed __int64 leftValue; // rt2
  int keyValue1; // edi
  char v45; // al
  int v46; // ebx
  int v47; // eax
  signed int v48; // eax
  int v49; // edx
  char *v50; // ecx
  int v51; // eax
  int v52; // ebx
  bool v53; // zf
  _DWORD *v54; // eax
  int curIndex2; // [esp+0h] [ebp-2C0Ch]
  int sn_value; // [esp+4h] [ebp-2C08h]
  int *dataSn; // [esp+18h] [ebp-2BF4h]
  int max; // [esp+1Ch] [ebp-2BF0h]
  int v60; // [esp+20h] [ebp-2BECh]
  int m_Index; // [esp+24h] [ebp-2BE8h]
  int v62; // [esp+28h] [ebp-2BE4h]
  int index; // [esp+2Ch] [ebp-2BE0h]
  int stepIndex; // [esp+30h] [ebp-2BDCh]
  int v65; // [esp+34h] [ebp-2BD8h]
  int curIndex; // [esp+38h] [ebp-2BD4h]
  int keyValue; // [esp+3Ch] [ebp-2BD0h]
  int m; // [esp+40h] [ebp-2BCCh]
  int m2; // [esp+44h] [ebp-2BC8h]
  int snLen; // [esp+48h] [ebp-2BC4h]
  int v71; // [esp+4Ch] [ebp-2BC0h]
  int step; // [esp+50h] [ebp-2BBCh]
  char *(__cdecl *v73)(int, int, __int64, _BYTE *, int); // [esp+64h] [ebp-2BA8h]
  int *v74; // [esp+68h] [ebp-2BA4h]
  int *v75; // [esp+6Ch] [ebp-2BA0h]
  void *v76; // [esp+70h] [ebp-2B9Ch]
  int *v77; // [esp+74h] [ebp-2B98h]
  struct vector lastKeyTable; // [esp+80h] [ebp-2B8Ch]
  struct vector v79; // [esp+8Ch] [ebp-2B80h]
  struct vector keyVector; // [esp+98h] [ebp-2B74h]
  struct vector temKeyValueVetor; // [esp+A4h] [ebp-2B68h]
  int inputSn; // [esp+C0h] [ebp-2B4Ch]
  unsigned __int8 v83; // [esp+1C0h] [ebp-2A4Ch]
  int v84; // [esp+2C0h] [ebp-294Ch]
  struct DataTable newKeyTable; // [esp+3C0h] [ebp-284Ch]
  struct DataTable key2Table; // [esp+17D0h] [ebp-143Ch]
  int v87; // [esp+2BE0h] [ebp-2Ch]
  int *v88; // [esp+2BE8h] [ebp-24h]
  int v89; // [esp+2BECh] [ebp-20h]
  int v90; // [esp+2BF0h] [ebp-1Ch]
  int v91; // [esp+2BF4h] [ebp-18h]
  int v92; // [esp+2BF8h] [ebp-14h]
  int v93; // [esp+2BFCh] [ebp-10h]
  int retaddr; // [esp+2C0Ch] [ebp+0h]

  v93 = retaddr;
  v92 = v4;
  v91 = cur1;
  v90 = v6;
  v89 = v3;
  v88 = &argc;
  v7 = alloca(11240);
  v73 = sub_4B85B0;
  v74 = dword_4B9D1C;
  v76 = &loc_4B9827;
  v75 = &v87;
  v77 = &curIndex2;
  sub_40D9D0(&v71);
  sub_40C510();
  ChangeKeyByAddr(v8, v9, v6, 0, 0x25A);
  step = -1;
  ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
  create0x400Random(&newKeyTable);
  step = 1;
  create0x400Random(&key2Table);
  step = 2;
  sub_4B5240((int)&stdio, &inputSn);
  for ( snLen = 0; ; ++snLen )
  {
    v13 = snLen;
    if ( !*((_BYTE *)&v92 + snLen - 0x2B38) )
      break;
  }
  i = 0;
  LOBYTE(v3) = 0x37;
  while ( i != snLen )
  {
    LOBYTE(v13) = *((_BYTE *)&v92 + i - 0x2B38);// sn
    LOBYTE(v12) = '0';
    if ( (char)v13 > '9' )
    {
      LOBYTE(v12) = '=';
      if ( (char)v13 < 'a' )
        v12 = v3;
    }
    v15 = v13 - v12;
    *((_BYTE *)&v92 + i - 0x2A38) = v15;        // data_sn
    v13 = v15 - 1;
    if ( (unsigned __int8)v13 > 0xEu )
      goto LABEL_61;
    ++i;
  }
  v16 = (char *)&v84;
  dataSN = &v83;
  *((_BYTE *)&v92 + snLen - 0x2A38) = 0;
  while ( snLen )
  {
    dataSnEnd = &v83 + snLen;
    do
    {
      v19 = *dataSnEnd % 0xAu;
      *dataSnEnd /= 0xAu;
      *(dataSnEnd-- - 1) += 16 * v19;
    }
    while ( &v83 != dataSnEnd );
    v20 = v83 % 0xAu;
    v83 /= 0xAu;
    *v16 = v20;                                 // 余数
    do
    {
      cur1 = snLen;
      v21 = snLen - 1;
      if ( *(&v83 + snLen - 1) )
        break;
      --snLen;
    }                                           // ((c0*0X0a+c1)*0x0a + c2) ....
    while ( v21 );
    ++v16;
  }
  step = 2;
  SetTableAndDiv0x0A(&newKeyTable, &source, 0x10);
  sn_value = SetTableAndDiv0x0A(&key2Table, &byte_4BC088, 16);
  table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);
  curIndex2 = cur1;
  CallTableDiv(&newKeyTable);                   // 转换成new constKeyTable 
  lastKeyTable.start = 0;
  lastKeyTable.last = 0;
  lastKeyTable.end = 0;
  v62 = 0;
  v65 = 0;
  index = 0;
  m = 0;
  while ( 1 )
  {
    step = 3;
    num = GetTableNum(&newKeyTable);
    if ( index >= num )
      break;
    keyValue = GetTableValueByIndex(&newKeyTable, index);
    keyVector.start = 0;
    keyVector.last = 0;
    keyVector.end = 0;
    tempBuf = (int *)malloc_0(0x510);
    malocBufEnd = tempBuf + 0x144;
    keyVectorBuf = tempBuf;
    keyVector.start = tempBuf;
    k = 0;
    keyVector.end = malocBufEnd;
    do
    {
      keyVectorBuf[k] = 0;                      // clear buf
      ++k;
    }
    while ( k != 0x144 );
    keyVector.last = malocBufEnd;
    if ( keyValue )
    {
      if ( keyValue <= 9 )
      {
        m1 = m;
        keyVectorBuf[(_DWORD)m1] = 1;
        leftValue = m1 % 9;
        keyValue1 = keyValue;
        keyVectorBuf[keyValue + 9 * (unsigned int)(m1 / 9) + 0x50] = 1;
        LODWORD(m1) = keyValue1 + 9 * (unsigned __int64)(m1 % 9) + 0xA1;
        cur1 = 3;
        keyVectorBuf[(_DWORD)m1] = 1;
        dataSN = (unsigned __int8 *)keyValue;
        keyVectorBuf[keyValue + 9 * (3 * (m / 27) + (signed int)leftValue / 3) + 0xF2] = 1;
        step = 4;
        Vector_push(&lastKeyTable, &keyVector);
        stepIndex = v65 + 1;
        sn_value = SetTableValueByIndex(&g_snTable, v65, keyValue);// 对于constKey 小于等于9 插入到g_snTable中,大于不放
        curIndex2 = sn_value;
        ++m;
      }
      else
      {
        curIndex = 0;
        dataSn = (int *)((char *)&v92 + v62 - 0x2938);// 获取SN指针
        while ( 1 )
        {
          m_Index = curIndex + v62;
          stepIndex = curIndex + v65;
          m2 = curIndex + m;
          if ( curIndex >= keyValue - 9 )
            break;
          curIndex1 = curIndex;
          sn_value = *((unsigned __int8 *)dataSn + curIndex);// 取出SN
          step = 4;
          SetTableValueByIndex(&g_snTable, stepIndex, sn_value);
          sn_value = curIndex1;
          curIndex2 = curIndex1;
          m_Index = 4 * m2;
          muti9_Value = 9 * (m2 / 9);
          stepIndex = 36 * (m2 / 9) + 0x144;
          max = 36 * (m2 / 9) + 0x168;
          v60 = 4 * (9 * (m2 % 9) - muti9_Value);
          m2 = 4 * (9 * (m2 % 9 / 3 + 3 * (m2 / 27)) - muti9_Value);
          do
          {
            temKeyValueVetor.start = 0;
            temKeyValueVetor.last = 0;
            temKeyValueVetor.end = 0;
            step = 4;
            tempBuf1 = (int *)malloc_0(0x510);
            temKeyValueVetor.start = tempBuf1;
            i1 = 0;
            temKeyValueVetor.end = tempBuf1 + 0x144;
            do
            {
              tempBuf1[i1] = 0;
              ++i1;
            }
            while ( i1 != 0x144 );
            cur1 = stepIndex;
            v31 = v60;
            temKeyValueVetor.last = tempBuf1 + 0x144;
            *(int *)((char *)tempBuf1 + m_Index) = 1;// 0
            *(int *)((char *)tempBuf1 + cur1) = 1;// 51
            pmalloc2Buf = (int *)((char *)tempBuf1 + v31);
            v33 = (int *)((char *)tempBuf1 + m2);
            *(int *)((char *)pmalloc2Buf + cur1 + 0x144) = 1;// A1
            *(int *)((char *)v33 + cur1 + 0x288) = 1;// F2
            step = 5;
            Vector_push(&lastKeyTable, &temKeyValueVetor);
            curIndex2 = v34;
            free_0((int *)&temKeyValueVetor);
            stepIndex += 4;
            dataSN = (unsigned __int8 *)stepIndex;
          }
          while ( max != stepIndex );
          ++curIndex;
        }
        step = 4;
        nextKeyValue = GetTableValueByIndex(&newKeyTable, index + 1);
        curIndex2 = v36;
        if ( nextKeyValue <= 9 )
        {
          v62 = m_Index;
          m = m2;
        }
        else
        {
          m = 0;
          keyValue = 0;
          do
          {
            v37 = *(int *)((char *)&off_4BC020 + keyValue);
            step = 4;
            ++m;                                // 应该等于9
            keyValue += 4;
          }
          while ( keyValue != 0x24 );
          v38 = keyVector.start;
          cnt_9 = m;
          m3 = m2;
          keyVector.start[m3] = 1;
          v41 = m3 % 9;
          v38[cnt_9 + 9 * (unsigned int)(m3 / 9) + 0x50] = 1;
          LODWORD(m3) = cnt_9 + 9 * (unsigned __int64)(m3 % 9) + 0xA1;
          cur1 = 3;
          v38[(_DWORD)m3] = 1;
          dataSN = (unsigned __int8 *)m;
          v38[m + 9 * (3 * (m2 / 27) + (signed int)v41 / 3) + 0xF2] = 1;
          step = 4;
          curIndex2 = (int)Vector_push(&lastKeyTable, &keyVector);
          m = m2 + 1;
          v62 = m_Index;
        }
      }
    }
    else
    {
      stepIndex = v65;
    }
    free_0((int *)&keyVector);
    ++index;
    v65 = stepIndex;
  }
  step = 3;
  sub_402BEE(
    &temKeyValueVetor,
    (int)&lastKeyTable,
    0xAAAAAAAB * ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2),
    0x144);
  step = 6;
  v45 = sub_402DB6(&temKeyValueVetor, 0);
  curIndex2 = cur1;
  if ( v45 )
  {
    step = 6;
    vectorCpy(&v79, (struct vector *)((char *)&temKeyValueVetor + 4));
    curIndex2 = (int)dataSN;
    m = 0;
    keyValue = 0;
    do
    {
      v46 = keyValue;
      curIndex2 = (int)&lastKeyTable.start[3 * (*(int *)((char *)v79.start + keyValue) - 1)];
      step = 8;
      vectorCpy(&keyVector, (struct vector *)curIndex2);
      curIndex2 = v46;
      m2 = 0;
      do
      {
        if ( keyVector.start[m2] == 1 )
          break;
        ++m2;
      }
      while ( m2 != 81 );
      if ( m2 == 0x28 )
      {
        --m;
      }
      else
      {
        m2 -= m2 >= 41;
        v47 = 0;
        do
        {
          if ( keyVector.start[v47 + 81] == 1 )
            break;
          ++v47;
        }
        while ( v47 != 81 );
        curIndex = v47 % 9 + 1;
        step = 7;
        GetTableValueByIndex(&g_snTable, m2);
        v65 = (int)off_4BC060;
        v48 = GetTableValueByIndex(&g_snTable, m2);
        curIndex2 = v49;
        m += curIndex == *(unsigned __int8 *)(v65 + v48);
      }
      free_0((int *)&keyVector);
      keyValue += 4;
    }
    while ( keyValue != 0x144 );
    v50 = off_4BC05C;
    v51 = 0;
    do
    {
      v52 = (unsigned __int8)v50[v51];
      snLen += 9 * (v52 ^ m) ^ 0x37;
      v53 = m == v52;
      v50[v51] = v52 ^ m;
      if ( v53 )
        break;
      ++v51;
    }
    while ( v51 != 0x201 );
    if ( snLen == 0x1F1A )                      // 成功
    {
      step = 8;
      v54 = (_DWORD *)sub_4B3F00((int)&dword_4BD9A0, off_4BC05C);// 输出
      sub_4B0DB0(v54);
    }
    free_0((int *)&v79);
  }
  j_free(temKeyValueVetor.start);
  free_0((int *)&temKeyValueVetor.last);
  sub_402966((int *)&lastKeyTable);
LABEL_61:
  nop();
  nop();
  sub_40DA40(&v71);
  return 0;
}
流程如下:
1、调用 40D9D0  40C510 进行初始化变量同时初始化g_snTable(4C8020)用于最后校验的一个表,里面包含输入sn信息。
2、进行如下调用,
ChangeKeyByAddr  
ChangeKeyByAddr  
ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);
ChangeKeyAndAntiDebug(v10, v11, v3, v6, 0x1000);

 计算出2个常数 ,我们称之为 constKey1 ,constKey2,如下:

 计算出2个常数 ,我们称之为 constKey1 ,constKey2,如下:

4BC080 该值为: 0x1093ACBD

4BC080 该值为: 0x1093ACBD

         4BC084 该值为:  0x2cF346

3、调用  create0x400Random 函数 将变量 key1Table和key2table 初始化,后面会将 0x1093ACBD与 0x2cF346放入其中

         4BC084 该值为:  0x2cF346

3、调用  create0x400Random 函数 将变量 key1Table和key2table 初始化,后面会将 0x1093ACBD与 0x2cF346放入其中
create0x400Random(&key1Table );
create0x400Random(&key1Table );
create0x400Random(&key2Table); 
create0x400Random(&key2Table); 
1) create0x400Random函数,如下:
这个表的结构如下
00000000 vtable          dd ?
00000004 num             dd ?                    ; XREF: table_mul_oneValue+A7/r
00000008 value           db 1024 dup(?)
00000408 index           dd 1024 dup(?)
00001408 clock1          dd ?
0000140C clock2          dd ?
00001410 DataTable       ends
00000000 vtable          dd ?
00000004 num             dd ?                    ; XREF: table_mul_oneValue+A7/r
00000008 value           db 1024 dup(?)
00000408 index           dd 1024 dup(?)
00001408 clock1          dd ?
0000140C clock2          dd ?
00001410 DataTable       ends

利用clock生成随机数,放在index数组里面,然后根据index的索引定位value数组的位置。
为了分析方便,直接将生成随机数的代码bypass掉,使其顺序为0-0x3FF,这样观察表中的数据比较清晰直观。相应的函数如下:

signed int __thiscall create0x400Random(struct DataTable *this)
{
  struct DataTable *v1; // ST0C_4
  int v2; // eax

  this->vtable = (int)off_4C5F30;
  v1 = this;
  v2 = clock();
  v1->clock2 = v2;
  v1->clock1 = v2;
  return create0x400RandomByClock(v1);
}

signed int __thiscall create0x400RandomByClock(struct DataTable *this)
{
  signed int result; // eax

  result = 0;
  do
  {
    this->index[result] = result;
    ++result;
  }
  while ( result != 0x400 );
//去掉后面的随机代码,让函数直接返回
  return result;
}
4、调用sub_4B5240 获取输入的sn
     将sn转换为数字,并且要求输入的字符必须是  123456789ABCDEF,其他的都是非法字符,尤其是 0字符。
     将转换为数字的sn再次进行16to10进制转换,此时生成的为一个10进制大数。比如输入是‘ABC‘’,则对应的数据为 ‘8 5 2 3‘ 小端存储。
5、调用SetTable_16To10函数
       1、将上面的两个常量放入到前面初始化的2个结构体中:key1Table和key2table

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax

  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if ( this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

signed int __thiscall create0x400Random(struct DataTable *this)
{
  struct DataTable *v1; // ST0C_4
  int v2; // eax

  this->vtable = (int)off_4C5F30;
  v1 = this;
  v2 = clock();
  v1->clock2 = v2;
  v1->clock1 = v2;
  return create0x400RandomByClock(v1);
}

signed int __thiscall create0x400RandomByClock(struct DataTable *this)
{
  signed int result; // eax

  result = 0;
  do
  {
    this->index[result] = result;
    ++result;
  }
  while ( result != 0x400 );
//去掉后面的随机代码,让函数直接返回
  return result;
}
4、调用sub_4B5240 获取输入的sn
     将sn转换为数字,并且要求输入的字符必须是  123456789ABCDEF,其他的都是非法字符,尤其是 0字符。
     将转换为数字的sn再次进行16to10进制转换,此时生成的为一个10进制大数。比如输入是‘ABC‘’,则对应的数据为 ‘8 5 2 3‘ 小端存储。
5、调用SetTable_16To10函数
       1、将上面的两个常量放入到前面初始化的2个结构体中:key1Table和key2table

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax

  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if ( this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

signed int __thiscall create0x400Random(struct DataTable *this)
{
  struct DataTable *v1; // ST0C_4
  int v2; // eax

  this->vtable = (int)off_4C5F30;
  v1 = this;
  v2 = clock();
  v1->clock2 = v2;
  v1->clock1 = v2;
  return create0x400RandomByClock(v1);
}

signed int __thiscall create0x400RandomByClock(struct DataTable *this)
{
  signed int result; // eax

  result = 0;
  do
  {
    this->index[result] = result;
    ++result;
  }
  while ( result != 0x400 );
//去掉后面的随机代码,让函数直接返回
  return result;
}
4、调用sub_4B5240 获取输入的sn
     将sn转换为数字,并且要求输入的字符必须是  123456789ABCDEF,其他的都是非法字符,尤其是 0字符。
     将转换为数字的sn再次进行16to10进制转换,此时生成的为一个10进制大数。比如输入是‘ABC‘’,则对应的数据为 ‘8 5 2 3‘ 小端存储。
5、调用SetTable_16To10函数
       1、将上面的两个常量放入到前面初始化的2个结构体中:key1Table和key2table

       2、同时将 将2个表中的数据由16进制转换为10进制。  0x1093ACBD  -->278113469    0x2cF346 ->2945862

       

int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax

  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if ( this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

int __thiscall SetTable_16To10(struct DataTable *this, _BYTE *source, int len)
{
  _BYTE *p; // eax
  int curNum; // edx
  struct DataTable *v5; // esi
  int curNum_1; // eax

  this->num = 0;
  for ( p = source; *p; this->value[v5->index[1]] = *(p - 1) & 0xF )
  {
    curNum = this->num;
    ++p;
    v5 = (struct DataTable *)((char *)this + 4 * curNum);
    this->num = curNum + 1;
    this->value[v5->index[0]] = (signed int)(unsigned __int8)*(p - 1) >> 4;
    this->num = curNum + 2;
  }
  while ( 1 )
  {                                             // 去掉0
    curNum_1 = this->num;
    if ( this->value[*(_DWORD *)&this->value[4 * curNum_1 + 0x3FC]] )
      break;
    this->num = curNum_1 - 1;
  }
  return TableDiv(this, len, 0xA);
}
6、调用table_Mul_Tablue将上面的2个10进制数据进行相乘。使其放入到 newKeyTable中。

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

table_Mul_Tablue((struct DataTable *)v16, &newKeyTable, &key2Table);

signed int __userpurge table_Mul_Tablue@<eax>(struct DataTable *key1Table@<ebx>, struct DataTable *a2@<ecx>, struct DataTable *key2Table)
{
  int i; // esi
  void *v4; // esp
  struct DataTable *v5; // ecx
  struct DataTable *key1Table_1; // ebx
  int value; // ST00_4
  signed int v9; // edx
  int v10; // eax
  bool v11; // zf
  bool v12; // sf
  unsigned __int8 v13; // of
  struct DataTable tempVtable1; // [esp+Ch] [ebp-2838h]
  struct DataTable tempVtable2; // [esp+141Ch] [ebp-1428h]
  int div_result; // [esp+2838h] [ebp-Ch]

  sub_40D480(0x284Cu, (int)a2, div_result);
  i = 0;
  v4 = alloca(10316);
  key1Table_1 = v5;
  create0x400Random(&tempVtable1);
  div_result = CreatetTableAndSetValue(&tempVtable2, 0);
  if ( key1Table_1->num + key2Table->num > 0x400 )
    return 1;
  while ( i < key2Table->num )
  {
    value = (unsigned __int8)key2Table->value[key2Table->index[i]];
    tabeCopy(&tempVtable1, key1Table_1);
    tableRoR(&tempVtable1, i);
    table_mul_oneValue(&tempVtable1, value);
    v10 = table_add(&tempVtable2, v9, &tempVtable1);
    v13 = __OFSUB__(key1Table_1->num, 0x3FF);
    v11 = key1Table_1->num == 0x3FF;
    v12 = key1Table_1->num - 0x3FF < 0;
    div_result = v10;
    if ( !((unsigned __int8)(v12 ^ v13) | v11) )
      return 1;
    ++i;
  }
  create0x400RandomByClock(key1Table_1);
  tabeCopy(key1Table_1, &tempVtable2);
  return 0;
}
7、调用table_10to16 将  newKeyTable再次转换成16进制。

signed int __userpurge table_Mul_Tablue@<eax>(struct DataTable *key1Table@<ebx>, struct DataTable *a2@<ecx>, struct DataTable *key2Table)
{
  int i; // esi
  void *v4; // esp
  struct DataTable *v5; // ecx
  struct DataTable *key1Table_1; // ebx
  int value; // ST00_4
  signed int v9; // edx
  int v10; // eax
  bool v11; // zf
  bool v12; // sf
  unsigned __int8 v13; // of
  struct DataTable tempVtable1; // [esp+Ch] [ebp-2838h]
  struct DataTable tempVtable2; // [esp+141Ch] [ebp-1428h]
  int div_result; // [esp+2838h] [ebp-Ch]

  sub_40D480(0x284Cu, (int)a2, div_result);
  i = 0;
  v4 = alloca(10316);
  key1Table_1 = v5;
  create0x400Random(&tempVtable1);
  div_result = CreatetTableAndSetValue(&tempVtable2, 0);
  if ( key1Table_1->num + key2Table->num > 0x400 )
    return 1;
  while ( i < key2Table->num )
  {
    value = (unsigned __int8)key2Table->value[key2Table->index[i]];
    tabeCopy(&tempVtable1, key1Table_1);
    tableRoR(&tempVtable1, i);
    table_mul_oneValue(&tempVtable1, value);
    v10 = table_add(&tempVtable2, v9, &tempVtable1);
    v13 = __OFSUB__(key1Table_1->num, 0x3FF);
    v11 = key1Table_1->num == 0x3FF;
    v12 = key1Table_1->num - 0x3FF < 0;
    div_result = v10;
    if ( !((unsigned __int8)(v12 ^ v13) | v11) )
      return 1;
    ++i;
  }
  create0x400RandomByClock(key1Table_1);
  tabeCopy(key1Table_1, &tempVtable2);
  return 0;
}
7、调用table_10to16 将  newKeyTable再次转换成16进制。
signed int __userpurge table_Mul_Tablue@<eax>(struct DataTable *key1Table@<ebx>, struct DataTable *a2@<ecx>, struct DataTable *key2Table)
{
  int i; // esi
  void *v4; // esp
  struct DataTable *v5; // ecx
  struct DataTable *key1Table_1; // ebx
  int value; // ST00_4
  signed int v9; // edx
  int v10; // eax
  bool v11; // zf
  bool v12; // sf
  unsigned __int8 v13; // of
  struct DataTable tempVtable1; // [esp+Ch] [ebp-2838h]
  struct DataTable tempVtable2; // [esp+141Ch] [ebp-1428h]
  int div_result; // [esp+2838h] [ebp-Ch]

  sub_40D480(0x284Cu, (int)a2, div_result);
  i = 0;
  v4 = alloca(10316);
  key1Table_1 = v5;
  create0x400Random(&tempVtable1);
  div_result = CreatetTableAndSetValue(&tempVtable2, 0);
  if ( key1Table_1->num + key2Table->num > 0x400 )
    return 1;
  while ( i < key2Table->num )
  {
    value = (unsigned __int8)key2Table->value[key2Table->index[i]];
    tabeCopy(&tempVtable1, key1Table_1);
    tableRoR(&tempVtable1, i);
    table_mul_oneValue(&tempVtable1, value);
    v10 = table_add(&tempVtable2, v9, &tempVtable1);
    v13 = __OFSUB__(key1Table_1->num, 0x3FF);
    v11 = key1Table_1->num == 0x3FF;
    v12 = key1Table_1->num - 0x3FF < 0;
    div_result = v10;
    if ( !((unsigned __int8)(v12 ^ v13) | v11) )
      return 1;
    ++i;
  }
  create0x400RandomByClock(key1Table_1);
  tabeCopy(key1Table_1, &tempVtable2);
  return 0;
}
7、调用table_10to16 将  newKeyTable再次转换成16进制。
       table_10to16(&newKeyTable);
int __thiscall table_10to16(struct DataTable *this)
{
  return TableDiv(this, 10, 16);
}
8、里程碑,此时会生成一个长度为2A的16进制数据作为一个固定的key将参与到后面的计算中。这个key的数值入下:

char constKey2A[0x2A] =
	{ 
		0x0B, 0x07, 0x09, 0x0F, 0x03, 0x0D, 0x04, 0x0B, 0x09, 0x0D, 0x05, 0x0A, 0x06, 0x0B, 0x08, 0x0C,
		0x02, 0x03, 0x0B, 0x06, 0x0C, 0x0B, 0x01, 0x0C, 0x03, 0x05, 0x0D, 0x04, 0x0B, 0x05, 0x0A, 0x01,
		0x0B, 0x07, 0x0B, 0x02, 0x0F, 0x08, 0x0E, 0x03, 0x05, 0x0B 
	};
9、生成2个大的数据结构:
int __thiscall table_10to16(struct DataTable *this)
{
  return TableDiv(this, 10, 16);
}
8、里程碑,此时会生成一个长度为2A的16进制数据作为一个固定的key将参与到后面的计算中。这个key的数值入下:

char constKey2A[0x2A] =
	{ 
		0x0B, 0x07, 0x09, 0x0F, 0x03, 0x0D, 0x04, 0x0B, 0x09, 0x0D, 0x05, 0x0A, 0x06, 0x0B, 0x08, 0x0C,
		0x02, 0x03, 0x0B, 0x06, 0x0C, 0x0B, 0x01, 0x0C, 0x03, 0x05, 0x0D, 0x04, 0x0B, 0x05, 0x0A, 0x01,
		0x0B, 0x07, 0x0B, 0x02, 0x0F, 0x08, 0x0E, 0x03, 0x05, 0x0B 
	};
9、生成2个大的数据结构:
char constKey2A[0x2A] =
	{ 
		0x0B, 0x07, 0x09, 0x0F, 0x03, 0x0D, 0x04, 0x0B, 0x09, 0x0D, 0x05, 0x0A, 0x06, 0x0B, 0x08, 0x0C,
		0x02, 0x03, 0x0B, 0x06, 0x0C, 0x0B, 0x01, 0x0C, 0x03, 0x05, 0x0D, 0x04, 0x0B, 0x05, 0x0A, 0x01,
		0x0B, 0x07, 0x0B, 0x02, 0x0F, 0x08, 0x0E, 0x03, 0x05, 0x0B 
	};
9、生成2个大的数据结构:
a、多个510buf 组成的vector;
b、sn与constKey2A混合在一起放入到g_sn_table中
a、多个510buf 组成的vector;
a、多个510buf 组成的vector;
b、sn与constKey2A混合在一起放入到g_sn_table中
a、对 constKey2A进行索引,当索引到0x2A个数据时就结束循环。
b、如果 constKey2A的值小于9生成一个510BUF,同时将对应小于A的值放入到 g_sn_table中。继续下一个循环
c、 如果constKey2A的值大于9, 则索引输入的10进制sn数据,放入 (x-9)个字符到 g_sn_table中,同时生成  (x-9)*9个510buf放入到vector中。
d、如果本次 constKey2A的值大于9,同时下一个也大于9,则进入到反调试流程,调用9次反调试函数,返回值为9,根据这个计数9来初始化一个510的buf,如果存在调试器,则计算的数据将使错误的。
e 、将510的buf分成4个部分每个部分长度为可以放入0x51个整数。其中0-50 放入的是索引,51-F1放入的是key值,F2开始的与余数有关。里面的数据时用索引来表示值的,如果该索引位置的数据为1,则表示该值对应的索引为相依的数据信息。
最后生成2个数据其中一个是 510buf 组成的vector 其并不与输入的sn相关,而是只与 constKey2A相关,可以认为是不变的数据。 g_sn_table放入的是 constKey2A与输入的sn的混合。放入的规则为:
a、对 constKey2A进行索引,当索引到0x2A个数据时就结束循环。
b、如果 constKey2A的值小于9生成一个510BUF,同时将对应小于A的值放入到 g_sn_table中。继续下一个循环
c、 如果constKey2A的值大于9, 则索引输入的10进制sn数据,放入 (x-9)个字符到 g_sn_table中,同时生成  (x-9)*9个510buf放入到vector中。
d、如果本次 constKey2A的值大于9,同时下一个也大于9,则进入到反调试流程,调用9次反调试函数,返回值为9,根据这个计数9来初始化一个510的buf,如果存在调试器,则计算的数据将使错误的。
e 、将510的buf分成4个部分每个部分长度为可以放入0x51个整数。其中0-50 放入的是索引,51-F1放入的是key值,F2开始的与余数有关。里面的数据时用索引来表示值的,如果该索引位置的数据为1,则表示该值对应的索引为相依的数据信息。
最后生成2个数据其中一个是 510buf 组成的vector 其并不与输入的sn相关,而是只与 constKey2A相关,可以认为是不变的数据。 g_sn_table放入的是 constKey2A与输入的sn的混合。放入的规则为:
1、如果 constKey2A[i] 大于10, 则放入  constKey2A[i]-10个sn数据到 g_sn_table 中,
2、如果小于10 ,则直接 constKey2A[i]放入 g_sn_table 中。
1、如果 constKey2A[i] 大于10, 则放入  constKey2A[i]-10个sn数据到 g_sn_table 中,
2、如果小于10 ,则直接 constKey2A[i]放入 g_sn_table 中。

10、调用  sub_402BEE
         根据前面的510 buf跟上以及一个常量 0x144生成了一个vector 链表结构,并对其进行初始化,调用如下:
       sub_402BEE(&temKeyValueVetor,(int)&lastKeyTable, ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2), 0x144);
该函数比较大,大概分析了下数据结构。里面分配了多个0x20大小的链表结构。
11、调用 sub_402DB6
       v45 = sub_402DB6(&temKeyValueVetor, 0);
        这个函数是个递归调用的函数,仔细分析发现其中存在如下调用:
.data:004BC044 11 24 40 00                         off_4BC044      dd offset sub_402411    ; DATA XREF: sub_402CD0+32↑r
.data:004BC048 4C 24 40 00                                         dd offset sub_40244C
.data:004BC04C 38 1F 40 00                                         dd offset sub_401F38
.data:004BC050 9C 24 40 00                                         dd offset sub_40249C
.data:004BC054 10 25 40 00                                         dd offset sub_402510

_DWORD *__thiscall sub_402CD0(_DWORD *this, _DWORD *a2)
{
  _DWORD *v2; // esi
  signed int v3; // eax
  int v4; // edx
  _DWORD *result; // eax
  _DWORD *i; // edx
  _DWORD *v7; // ecx
  int v8; // ecx

  v2 = this;
  v3 = this[6];
  if ( v3 <= 1199 )
    ((void (__usercall *)(int@<eax>))off_4BC044[v3 % 5])(v3 / 5 / 0x3C);
  v4 = a2[3];
  result = (_DWORD *)a2[2];
  ++v2[6];
  result[3] = v4;
  *(_DWORD *)(a2[3] + 8) = result;
  for ( i = (_DWORD *)a2[1]; i != a2; i = (_DWORD *)i[1] )
  {
    result = (_DWORD *)i[3];
    while ( i != result )
    {
      v7 = (_DWORD *)result[1];
      *v7 = *result;
      *(_DWORD *)(*result + 4) = v7;
      v8 = result[4];
      result = (_DWORD *)result[3];
      --*(_DWORD *)(v8 + 28);
    }
  }
  return result;
}
通过分析off_4BC044数组对应的5个函数,整个流程如下:
for (int j = 0; j < 0x04; j++)
{
		for (int i = 0; i < 0x3C; i++)
		{
			int m = g_xorTable1[i] & 0x7f;
			int n = g_xorTable2[i] & 0x7f;
			OutputDebugPrintf("0x%02x,0x%02x\n", m, n);
			int a = sntable[m];
			int b = sntable[n];
			a = (a * 9) ^ 0x37;
			b = (b * 9) ^ 0x37;
			sntable[m] = b;
			sntable[n] = a;
		}
}	
根据 4Bc098与4BC1D42个table表的值亦或0x7F后得到2个索引,将g_sntable的数据 乘以9并亦或0x37后进行交换。一共循环了 4*60次。
这部分明显对g_snTable进行了置换操作,需要判断最后的置换结构,因此写个程序进行了测试,让g_sntable[0x50]的值为0-4F,只进行置换不进行 乘以9并亦或0x37的操作,发现如下规律:


10、调用  sub_402BEE
         根据前面的510 buf跟上以及一个常量 0x144生成了一个vector 链表结构,并对其进行初始化,调用如下:
       sub_402BEE(&temKeyValueVetor,(int)&lastKeyTable, ((_DWORD)((char *)lastKeyTable.last - (char *)lastKeyTable.start) >> 2), 0x144);
该函数比较大,大概分析了下数据结构。里面分配了多个0x20大小的链表结构。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-3-22 22:41 被oooAooo编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
2
其实程序只是在校验用户输入与固定值的匹配,属于明码校验的类型,只是比较绕而已
2019-3-25 18:11
0
游客
登录 | 注册 方可回帖
返回
//