亮点是十进制大数类(自带数据隐藏机制、校验阶段的特定调试检测),
校验算法主要是大数的幂结果特征(检验中也引入调试校验,而是时间差,致使限制在低次幂如平方的有效校验)
main函数规定ikey长度为[8,20]
要求(ikey*9)的n次幂的结果的中心位数值等于ikey[0],高位等于ikey[1:iken.len-1],且低位数字关于中心位与高位对称。
例如 ikey=12345679,(ikey*9)的平方为,12345678987654321,其各位数值满足上述条件 1234567 8-9-8 7654321
通过下述python代码,可以在短时间内(1秒左右)得到高位数匹配的ikey数集,
并得到上述的ikey=12345679为有效注册key,输入顺序低位在前,即 key = 97654321
#------- ------- ------- ------- ------- ------- -------
def eln(L=8,n=2):
f = sum([pow(10,r) for r in range(0,L)])+1
t = int((pow(pow(10,2*(L+1)-1),0.5)/9))
print("---"*3,"len:{}, n:{} from:{} to:{}".format(L,2,f,t),"---"*3)
for i in range(f,t,s):
istr = "{:d}".format(i)
m92str = "{:d}".format(int(pow(i*9,n)))
if istr[:istr.__len__()-1]==m92str[:istr.__len__()-1]:
print(istr[:istr.__len__()-1],m92str[:istr.__len__()-1],istr,m92str)
for L in range(8,21):
eln(L)
#------- ------- ------- ------- ------- ------- -------
高位数匹配的ikey数集输出结果
--------- len:8, n:2 from:11111112 to:35136418 ---------
1234567 1234567 12345675 12345670987655625
1234567 1234567 12345676 12345672987655056
1234567 1234567 12345677 12345674987654649
1234567 1234567 12345678 12345676987654404
1234567 1234567 12345679 12345678987654321 #----------------------命中满足所有校验条件的key
1234568 1234568 12345680 12345680987654400
1234568 1234568 12345681 12345682987654641
1234568 1234568 12345682 12345684987655044
1234568 1234568 12345683 12345686987655609
1234568 1234568 12345684 12345688987656336
--------- len:9, n:2 from:111111112 to:351364184 ---------
12345678 12345678 123456786 1234567818765433476
12345678 12345678 123456787 1234567838765432889
12345678 12345678 123456788 1234567858765432464
12345678 12345678 123456789 1234567878765432201
12345679 12345679 123456791 1234567918765432161
12345679 12345679 123456792 1234567938765432384
12345679 12345679 123456793 1234567958765432769
12345679 12345679 123456794 1234567978765433316
攻击过程
Ctrl+R,cmd执行exe程序样例,随机输入如1111111111回车,
得到提示信息"WRONG KEY...",
上IDA,SubView|String 索引到关联业务逻辑,实际是main函数中
.text:00401231 push offset aWrongKey___ ; "WRONG KEY...\n"
.text:00401236 call Hi_printf_sub_401BE0
.text:0040123B add esp, 4
.text:0040123E loc_40123E: ;
.text:0040123E lea ecx, [esp+4138h+loc_RandDigitNkey_xkey]
.text:00401245 mov [esp+4138h+var_4], 0FFFFFFFFh
.text:00401250 call Hi_RandDigitN_dtor_sub_401390
.text:00401255 jmp short loc_401288
.text:00401257 loc_401257: ;
.text:00401257 push offset aWellDone ; "WELL DONE!\n"
.text:0040125C call Hi_printf_sub_401BE0
.text:00401261 add esp, 4
.text:00401264 lea ecx, [esp+4138h+loc_RandDigitNkey_ikey]
.text:0040126B mov byte ptr [esp+4138h+var_4], 0
.text:00401273 call Hi_RandDigitN_dtor_sub_401390
整个判断逻辑在main函数中,其中许多自定义函数,
事实上这些自定义函数集是大数类的成员方法实现,用于实现大数运算。
对相关和所有自定义函数的全逆向分析重命名如下,大数的类定义参考RanDigitN
其中包括RanDigitN的内存布局的类成员,和下述成员函数,意义参考函数名
Hi_output_sub_4027B7
Hi_printf_sub_401BE0
Hi_u31_Pokemon_rand_sub_401A00 通用伪随机数产出器,随机因子为输入参数
Hi_RandDigitN_2008xrand_rand_1024_sub_4019E0 大数伪随机数产出器,随机因子为大数的随机因私xrand
Hi_RandDigitN_init_1008SRTbl_0008SRTblR_with_2008xrand_sub_401A60 根据大数的随机因子 初始化大数位权索引表和位权基数值表初始化
Hi_RandDigitN_imul_P1Nlt0A_sub_4016E0 大数与小于10的自然数相乘
Hi_RandDigitN_getRadix_forP1BitTh_sub_4013B0 获取大数相应位权的基数值
Hi_RandDigitN_getBitNum_sub_4013A0 获取大数的位长
Hi_RandDigitN_dtor_sub_401390 大数类析构函数
Hi_RandDigitN_ctor_lpszN_sub_401350 大数构造函数,重构初始化输入值为字符串表示的大数
Hi_RandDigitN_ctor_N_sub_401310 大数构造函数,重构初始化输入值为自然数
Hi_RandDigitN_ctor_1008SRTbl_0008SRTblR_with_CurTickCountAs2008xrandsub_4012C0 产生新的大数随机因子 并初始化大数位权索引表和位权基数值表初始化
Hi_RandDigitN_cmp_P1iRandDigitN_P2isPos_P3rsPos_P4cmpLen_P5bTailOrHead_sub_4013E0 比较两大数的特定位置特定长度的位权基数,可选比较大数的高位还是低位
Hi_RandDigitN_carry_sub_401970 大数进位操作,在执行大数加或乘等运算后需要处理进位
Hi_RandDigitN_assign_lpszN_sub_4014E0 大数赋值 输入值为字符串表示的大数
Hi_RandDigitN_assign_RandDigitN_sub_401540 大数赋值 输入值为大数
Hi_RandDigitN_assign_P1N_sub_4014A0 大数赋值 输入值为自然数
Hi_RandDigitN_add_RandDigitN_sub_4015E0 大数加运算 输入值为大数
Hi_RandDigitN_add_P1INT_sub_401580 大数加运算 输入值为自然数
Hi_RandDigitN_ShiftUp_P1Nbit_sub_401660 大数向上移位运算 输入值为移位个数 如 1234 向上移动一位 12340,移动两位123400
Hi_RandDigitN_EQ_IMUL_anyN_sub_401730 大数乘运算 输入值为自然数
Hi_RandDigitN_EQ_IMUL_RandDigitN_sub_401840 大数乘运算 输入值为大数
#define RAND_DIGIT_N_MAX_BIT_LENGTH 1024
//1024 is 0x400
//1024-1 is 0x3FF
public RandDigitN{
private:
unsigned int mBitLength; //this.04hww
unsigned int RandBitTable[RAND_DIGIT_N_MAX_BIT_LENGTH]; //this.08h cbSize:4*1024
unsigned int BitWeightIndexInRandBitTable[RAND_DIGIT_N_MAX_BIT_LENGTH];//this.1008h cbSize:4*1024
unsigned int xrand;//this.2008hww
unsigned int srand;//this.200Chww
public:
RandDigitN::RandDigitN();//Hi_RandDigitN_ctor_1008SRTbl_0008SRTblR_with_CurTickCountAs2008xrandsub_4012C0
RandDigitN::RandDigitN(unsigned int N);//Hi_RandDigitN_ctor_N_sub_401310
void RandDigitN::initialize_RandTables_with_srand()//Hi_RandDigitN_init_1008SRTbl_0008SRTblR_with_2008xrand_sub_401A60
unsigned int RandDigitN::get_rand();//Hi_RandDigitN_2008xrand_rand_1024_sub_4019E0
void RandDigitN::eq_imul(RandDigitN);//Hi_RandDigitN_EQ_IMUL_RandDigitN_sub_401840 eg. objN *= objM; is euqal to objN = objN * objM;
void RandDigitN::eq_imul(unsigned int N);//Hi_RandDigitN_EQ_IMUL_anyN_sub_401730
void RandDigitN::ShiftUp(unsigned int bitNum);//Hi_RandDigitN_ShiftUp_P1Nbit_sub_401660 eg. objN *= pow(10,bitNum)
void RandDigitN::add(RandDigitN ins);//Hi_RandDigitN_add_RandDigitN_sub_4015E0
void RandDigitN::assign(unsigned int N);//Hi_RandDigitN_assign_P1N_sub_4014A0
void RandDigitN::assign(RandDigitN ins);//Hi_RandDigitN_assign_RandDigitN_sub_401540
void RandDigitN::assign(char* lpszN);//Hi_RandDigitN_assign_lpszN_sub_4014E0
void RandDigitN::cmp(RandDigitN ins,
unsigned int ins_startPos,unsigned int self_startPos,
unsigned int cmp_length,bool bTailOrHead);//Hi_RandDigitN_cmp_P1iRandDigitN_P2isPos_P3rsPos_P4cmpLen_P5bTailOrHead_sub_4013E0
~RandDigitN();//Hi_RandDigitN_dtor_sub_401390
unsigned int RandDigitN::get_mBitLength();//Hi_RandDigitN_getBitNum_sub_4013A0
unsigned int RandDigitN::getBitRadix(unsigned int BitWeightIndex);// Hi_RandDigitN_getRadix_forP1BitTh_sub_4013B0 eg. RandDigitN(9687).getBitRadix(1) is 8
void RandDigitN::eq_imul(unsigned char littleN);//Hi_RandDigitN_imul_P1Nlt0A_sub_4016E0
void RandDigitN::add(unsigned int N);//Hi_RandDigitN_add_P1INT_sub_401580
void RandDigitN::carry();//Hi_RandDigitN_carry_sub_401970 call after all,imul,etc. operator to ajust the bit-weight-radix
}
public RandDigitN::RandDigitN(){
//Hi_RandDigitN_ctor_1008SRTbl_0008SRTblR_with_CurTickCountAs2008xrandsub_4012C0
this.srand = GetTickCount();
this.xrand = this.srand;
initialize_RandTables_with_srand();
}
public RandDigitN::initialize_RandTables_with_srand(){
//Hi_RandDigitN_init_1008SRTbl_0008SRTblR_with_2008xrand_sub_401A60
int i,t,r;
//
for(i = 0;i < RAND_DIGIT_N_MAX_BIT_LENGTH;i++){
this.BitWeightIndexInRandBitTable[i] = i & (RAND_DIGIT_N_MAX_BIT_LENGTH-1);
}
//randing BitWeightIndexInRandBitTable 使得位权基数索引表随机化
//大数RandDigitN的第i位(从低到高)的基数值存储在RandBitTable[BitWeightIndexInRandBitTable[i]]中
//即大数RandDigitN的各位上的基数值在RandBitTable表中随机存储,而不是我们常见的顺序存储
for(i = 0;i < RAND_DIGIT_N_MAX_BIT_LENGTH;i++){
t = this.BitWeightIndexInRandBitTable[i];
r = get_rand();
this.BitWeightIndexInRandBitTable[i] = r;
this.BitWeightIndexInRandBitTable[r] = t;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)