-
-
[原创] 看雪 CTF2018 第七题 限定域空间变换
-
2018-6-29 12:13 2347
-
0x00 业务逻辑与模型抽象
样例主体框架比较主观,main函数获取长度位16字节的输入key,
存放于全局变量00450B80 Hi_key db 10h dup(?) 处。然后通过
函数Hi_check_if_aK2iK_19xyzm_Ke_eq_Kr校验。校验函数步骤如下:
(1)将输入Hi_key映射为字符集Hi_szMapAI索引,构成初始K0
0040DA68 Hi_szMapAI db 'abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
(2)我们这里抽象一种有限域三维模型,
函数通过局部定义的"坐标选择向量"loc_A_dw64_b100h[16][16],经空间有限域Hi_xyzm将K0迭代变换19次得到Ke。
Hi_xyzm定义为全局变量,位于 0040FEF0 处。这里抽象为 char Hi_xyzm[x][y][z],其中x,y,z限定取值范围皆为0~63.
xyzm大小为64*64*64;
(3)最后将得到Ke与全局静态变量Kr(0040FEE0 Hi_Kr)比较,若匹配则映射出成功提示"yourserialisgood".
代码业务逻辑如下
int __cdecl main(int argc,const char**argv,const char**envp)
{
printf("Only 'a'-'z','A'-'Z','0'-'9' accepted.\n");
printf("Only 16 chars accepted.\n");
printf("Serial:");
scanf_s("%s",Hi_key,17);
Hi_check_if_aK2iK_19xyzm_Ke_eq_Kr();
system("PAUSE");
return 0;
}
int Hi_check_if_aK2iK_19xyzm_Ke_eq_Kr()
{
signed int loc_j;// ebx
signed int loc_kidx;// esi
signed int i;// eax
int loc_nKsize;// eax
char*loc_pKn_startPosRef;// ecx
signed int loc_A_WWIdx;// edi
char*loc_axes;// eax
int loc_PosN2;// esi
int v8;// ecx
int v9;// ecx
int v10;// ecx
signed int loc_i;// eax
_BYTE*loc_pKn_x;// [esp+Ch] [ebp-258h]
int loc_WWCntOfKNeed2Test_also_K0_N10h;// [esp+10h] [ebp-254h]
int loc_2N_nKsize;// [esp+14h] [ebp-250h]
char loc_xyz[3];// [esp+18h] [ebp-24Ch]
int loc_nKsize_ai;// [esp+1Ch] [ebp-248h]
KS loc_k0[20];// [esp+20h] [ebp-244h]
int loc_A_dw64_b100h[64];// [esp+160h] [ebp-104h]
loc_j=0;
loc_A_dw64_b100h[0]=65793;
loc_A_dw64_b100h[1]=0;
loc_A_dw64_b100h[2]=0;
loc_A_dw64_b100h[3]=0;
loc_A_dw64_b100h[4]=16777217;
loc_A_dw64_b100h[5]=1;
loc_A_dw64_b100h[6]=0;
loc_A_dw64_b100h[7]=0;
loc_A_dw64_b100h[8]=1;
loc_A_dw64_b100h[9]=65792;
loc_A_dw64_b100h[10]=0;
loc_A_dw64_b100h[11]=0;
loc_A_dw64_b100h[12]=256;
loc_A_dw64_b100h[13]=16777472;
loc_A_dw64_b100h[14]=0;
loc_A_dw64_b100h[15]=0;
loc_A_dw64_b100h[16]=256;
loc_A_dw64_b100h[17]=65537;
loc_A_dw64_b100h[18]=0;
loc_A_dw64_b100h[19]=0;
loc_A_dw64_b100h[20]=16842752;
loc_A_dw64_b100h[21]=0;
loc_A_dw64_b100h[22]=1;
loc_A_dw64_b100h[23]=0;
loc_A_dw64_b100h[24]=0x10000;
loc_A_dw64_b100h[25]=1;
loc_A_dw64_b100h[26]=256;
loc_A_dw64_b100h[27]=0;
loc_A_dw64_b100h[28]=0x1000000;
loc_A_dw64_b100h[29]=0x1000000;
loc_A_dw64_b100h[30]=0x10000;
loc_A_dw64_b100h[31]=0;
loc_A_dw64_b100h[32]=0;
loc_A_dw64_b100h[33]=256;
loc_A_dw64_b100h[34]=1;
loc_A_dw64_b100h[35]=1;
loc_A_dw64_b100h[36]=0;
loc_A_dw64_b100h[37]=0x10000;
loc_A_dw64_b100h[38]=0x1000000;
loc_A_dw64_b100h[39]=256;
loc_A_dw64_b100h[40]=0;
loc_A_dw64_b100h[41]=0x1000000;
loc_A_dw64_b100h[42]=0;
loc_A_dw64_b100h[43]=257;
loc_A_dw64_b100h[44]=0;
loc_A_dw64_b100h[45]=0;
loc_A_dw64_b100h[46]=16777472;
loc_A_dw64_b100h[47]=0x10000;
loc_A_dw64_b100h[48]=0;
loc_A_dw64_b100h[49]=0;
loc_A_dw64_b100h[50]=65537;
loc_A_dw64_b100h[51]=0x10000;
loc_A_dw64_b100h[52]=0;
loc_A_dw64_b100h[53]=0;
loc_A_dw64_b100h[54]=65792;
loc_A_dw64_b100h[55]=0x1000000;
loc_A_dw64_b100h[56]=0;
loc_A_dw64_b100h[57]=0;
loc_A_dw64_b100h[58]=0x1000000;
loc_A_dw64_b100h[59]=16777217;
loc_A_dw64_b100h[60]=0;
loc_A_dw64_b100h[61]=0;
loc_A_dw64_b100h[62]=0;
loc_A_dw64_b100h[63]=16843008;
loc_kidx=0;
do
{
for(i=0;;++i)
{
if(i>=64)
{
printf("input error\n");
system("PAUSE");
exit(-1);
}
if(Hi_szMapAI[i]==(unsigned __int8)Hi_key[loc_kidx])
break;
}
loc_k0[0].kx[loc_kidx++]=i;
}
while(loc_kidx<16);
printf("\n");
loc_nKsize=16;
loc_nKsize_ai=16;
loc_2N_nKsize=2-(_DWORD)&loc_k0[1];
do
{
loc_pKn_startPosRef=(char*)loc_k0+loc_nKsize;
loc_pKn_x=(char*)loc_k0+loc_nKsize;
loc_A_WWIdx=0;
do
{
loc_axes=loc_xyz;
loc_PosN2=(int)&loc_pKn_startPosRef[loc_2N_nKsize];
loc_WWCntOfKNeed2Test_also_K0_N10h=4;
do
{
v8=(loc_PosN2-2)%16;
if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+v8))
*loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+v8+loc_nKsize_ai);
v9=(loc_PosN2-1)%16;
if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+v9))
*loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+v9+loc_nKsize_ai);
if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+loc_PosN2%16))
*loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+loc_PosN2%16+loc_nKsize_ai);
v10=(loc_PosN2+1)%16;
if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+v10))
*loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+v10+loc_nKsize_ai);
loc_PosN2+=4;
--loc_WWCntOfKNeed2Test_also_K0_N10h;
}
while(loc_WWCntOfKNeed2Test_also_K0_N10h);
*loc_pKn_x=Hi_xyzm[64*((unsigned __int8)loc_xyz[1]+((unsigned __int8)loc_xyz[0]<<6))
+(unsigned __int8)loc_xyz[2]];
loc_A_WWIdx+=4;
loc_pKn_startPosRef=loc_pKn_x+++1;
}
while(loc_A_WWIdx<64);
loc_2N_nKsize-=16;
loc_nKsize=loc_nKsize_ai+16;
loc_nKsize_ai=loc_nKsize;
}
while(loc_nKsize<0x140);
loc_i=0;
do
{
if((unsigned __int8)loc_k0[19].kx[loc_i]!=Hi_Kr[loc_i])
return printf("serial error\n");
++loc_i;
}
while(loc_i<16);
do
printf("%c",(unsigned __int8)Hi_szMapAI[(unsigned int)(unsigned __int8)loc_k0[9].kx[loc_j++]>>1]);
while(loc_j<16);
return printf("\n");
}
0x01 提取数据并抽象模型
IDA+WINDBG,在校验函数下面完成局部定义的"坐标选择向量"loc_A_dw64_b100h[16][16]初始化处断下,
00401212 xor esi, esi
在断点处执行下属IDAPython脚本,得到"坐标选择向量"loc_A_dw64_b100h[16][16],我们定义为A
#------- ------- ------- ------- ------- ------- -------
A_addr = get_reg_value('ebp')-0x104
for i in xrange(0,0x100):#16*16
print "0x{:02X}, ".format(Byte(A_addr+i)),
if (i+1)%16 == 0:
print ""
print " ",
#------- ------- ------- ------- ------- ------- -------
A = [
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01]
同时我们也先dump出有限域空间,因为是全局变量,静态或动态情况下都可以;这里我们加载为mxyz矩阵。
savefile(r'C:\CTF2018\CTF07\mxyz', 0, 0x122FEF0, 64*64*64)
with open(r'C:\CTF2018\CTF07\mxyz','rb') as mxyzf:
mxyz = list(struct.unpack("<{}B".format(64*64*64),mxyzf.read()))
"坐标选择向量"与mxyz的变换原理:
(1)定义输入为k,输出为K,如何从k变换到K?
k = [k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15]
K = [K0,K1,K2,K3,K4,K5,K6,K7,K8,K9,K10,K11,K12,K13,K14,K15]
(2)以K0的获取为例:我们取上面A的第0x00行数据,其中0x01的位置,决定了选用的k值
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
可见,K0选用k的k0,k1,k2作为坐标,其中从左到右依次赋值给xyz,即x=k0,y=k1,z=k2;于是我们得到
K0 = mxyz[x][y][z] //若将mxyz看作一维数组,则K0 = mxyz[(x<<12)+(y<<6)+z]
(3)同样的机制,我们可以得到K的全部取值,则从k变换到K。
这里我们先假定所有的k到K经过A选出的三个坐标都是从左到右依次赋值给x,y,z作为mxyz的坐标。
实际上k[i]到K[i]选出的三个值,并不都是从左到右依次充当x,y,z的角色,为了简化模型,我们后续再修正。
"坐标选择向量"与mxyz的逆变换:
直觉上这么规律变换,再数学上应该存在有效的逆变换求解K到k的变换过程。
这里我们从k到K的变换过程,结合A的特征,尝试求解逆变换:解决K到k的问题。
若得解,即可从Kr逆变换求解19次得到输入的Ki。在样例中
Kr = [0x14, 0x22, 0x1E, 0x10, 0x38, 0x30, 0x18, 0x10, 0x04, 0x1A, 0x24, 0x08, 0x02, 0x26, 0x38, 0x2A]
(1)我们还是采用之前的定义
k = [k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15]
K = [K0,K1,K2,K3,K4,K5,K6,K7,K8,K9,K10,K11,K12,K13,K14,K15]
这里K = Kr作为实测样例,现在求k
直观的解法是mxyz.index(K[0]),即可得到 idx = (x<<12)+(y<<6)+(z),通过简单变换,就可得到x,y,z的值,
对K[0]即得到k0,k1,k2。
通过初步测试,mxyz.count(K[i]),i=1..15,解的个数都有4096个。通过对x,y,z解集的树形分类分析,
x x y
y z z
z y x
确定了x,y,z中任意两个,即可确定第三个。
如此,我们可以根据K[i]解集结合A特征,不断缩小解集范围,并最终得到唯一或多个解(实测证明不存在多个解,见后续分析说明)
#mxyz.index(K[i]) >> x,y,z
#由K[i]在有限域空间mxyz的位置,得到坐标
def axes2xyz(axes = 0):
xs = 64*64
ys = 64
zs = 1
rm = axes
x = rm / xs
rm = rm % xs
y = rm / ys
z = rm % ys
return struct.pack("<3B",x,y,z)
#找出K[i]在有限域空间mxyz的所有4069=64*64个可能位置的坐标集
#坐标集归纳为树结构x->y->z->None or x->-z->xyzstr
def r2xyzt(r=0x14,idx=0):
global mxyz
cnt = mxyz.count(r)
xyzt = {}
s = 0
for i in xrange(0,cnt):
axes = mxyz[s:].index(r)
xyz = axes2xyz(s+axes)
if idx == 0:
pass #xyz=xyz
elif idx in [1,2,3,4,7,8,9,10,11]:
xyz = xyz[2] + xyz[0] + xyz[1]
else:
xyz = xyz[1] + xyz[2] + xyz[0]
if xyz[0] not in xyzt:
xyzt[xyz[0]]={}
if xyz[1] not in xyzt[xyz[0]]:
xyzt[xyz[0]][xyz[1]]={}
if xyz[2] not in xyzt[xyz[0]][xyz[1]]:
#xyzt[xyz[0]][xyz[1]][xyz[2]]=xyz
xyzt[xyz[0]][xyz[1]][xyz[2]]=None
s = s+axes+1
return xyzt
#由K得到K[i],i=0..15的解集树组
def k2kets(ke=[]):
#ke = [0x14, 0x22, 0x1E, 0x10, 0x38, 0x30, 0x18, 0x10, 0x04, 0x1A, 0x24, 0x08, 0x02, 0x26, 0x38, 0x2A]
kets = []
#for i in ke:
for i in xrange(0,ke.__len__()):
kets.append(r2xyzt(ke[i],i))
print "r2xyzt({:02X}) ok!".format(ke[i])
return kets
#通过解集树组,结合A的特征,我们计算找出满足A特征的解。
#如此遍历计算所有解64*64*64种情况,可以检测是否有多解
#若不需要检测证明不存在多解,平均遍历64*64*32次可得到解
def kets2k(kets=None):
ks = []
for k0 in kets[0].keys(): #kets[0] >> k0 k1 k2
for k1 in kets[0][k0].keys(): #枚举 k0 64 种情形, k1 64 种情形
k2 = kets[0][k0][k1].keys()[0] #由A第0行可知: k0 k1 决定了唯一的k2
for k3 in kets[1][k0].keys(): #kets[1] >> k3 k4 #由A第1行可知:k0已知,枚举 k3 的 64 种情形
k4=kets[1][k0][k3].keys()[0] #由A第1行可知: k0 k3 决定了唯一的k4
k6=kets[4][k1][k4].keys()[0] #kets[4] >> k6 #由A第1行可知: k1 k4 决定了唯一的k6
k8=kets[5][k2][k3].keys()[0] #kets[5] >> k8
k5=xz2y(kets[2],k0,k6)[0] #kets[2] >> k5 if len > 2 raise Exception
k7=kets[3][k1][k5].keys()[0] #kets[3] >> k7
k9=kets[6][k2][k4].keys()[0] #kets[6] >> k9
ka=kets[7][k3][k7].keys()[0] #kets[7] >> ka
kc=kets[8][k5][k8].keys()[0] #kets[8] >> kc
kd=kets[10][k7][kc].keys()[0] #kets[10] >> kd
kb=xz2y(kets[9],k6,kd)[0] #kets[2] >> k5 if len > 2 raise Exception
ke1 = kets[11][k9][kb].keys()[0]
ke2 = kets[12][k8][ka].keys()[0]
if ke1!=ke2:
continue
ke=ke1
kf1 = kets[13][k9][ka].keys()[0]
kf2 = kets[14][kb][kc].keys()[0]
kf3 = kets[15][kd][ke].keys()[0]
if not ((kf1==kf2) and (kf2==kf3)):
continue
kf=kf1
#print ''.join([k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,ka,kb,kc,kd,ke,kf]).__repr__()
ks.append([k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,ka,kb,kc,kd,ke,kf])
return ks #返回唯一解,若移动至下面一行位置,则遍历返回所有可能解,也只有一个,这里减少不必要的遍历计算量
#return ks
#将Ki转换为输入字符Ka
def k2a(k=[]):
strs = 'abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
return b''.join([strs[ci] for ci in k])
#通过迭代求解我们得到输入的ki
#ke=Kr
ke = [0x14, 0x22, 0x1E, 0x10, 0x38, 0x30, 0x18, 0x10, 0x04, 0x1A, 0x24, 0x08, 0x02, 0x26, 0x38, 0x2A]
for i in xrange(0,19):
ke = kets2k(k2kets(ke))
if ke.__len__() > 1:
break
ke = [ord(c) for c in ke[0]]
ln = "ke{}=[".format(i+1)
for c in ke:
ln +="0x{:02X}, ".format(c)
print ln[:-2]+']'
以下为上述代码计算ke=Kr经十九次迭代得到的结果
ke = [0x14, 0x22, 0x1E, 0x10, 0x38, 0x30, 0x18, 0x10, 0x04, 0x1A, 0x24, 0x08, 0x02, 0x26, 0x38, 0x2A]
ke1=[0x0F, 0x0B, 0x07, 0x0B, 0x35, 0x03, 0x19, 0x1F, 0x0B, 0x31, 0x3B, 0x33, 0x03, 0x07, 0x15, 0x37]
ke2=[0x3A, 0x26, 0x00, 0x3A, 0x34, 0x06, 0x2C, 0x3C, 0x0E, 0x1E, 0x0A, 0x26, 0x24, 0x18, 0x3C, 0x18]
ke3=[0x0F, 0x07, 0x0D, 0x15, 0x23, 0x3F, 0x3F, 0x19, 0x11, 0x0D, 0x03, 0x25, 0x37, 0x3B, 0x19, 0x31]
ke4=[0x0C, 0x36, 0x16, 0x06, 0x06, 0x26, 0x04, 0x2E, 0x0C, 0x0C, 0x3A, 0x10, 0x10, 0x16, 0x36, 0x22]
ke5=[0x0F, 0x1F, 0x33, 0x0D, 0x2B, 0x2B, 0x19, 0x19, 0x3F, 0x33, 0x35, 0x2D, 0x27, 0x1B, 0x11, 0x07]
ke6=[0x3A, 0x12, 0x3C, 0x0E, 0x2C, 0x3C, 0x2E, 0x08, 0x1E, 0x22, 0x3C, 0x12, 0x26, 0x18, 0x0E, 0x0E]
ke7=[0x19, 0x2F, 0x03, 0x29, 0x15, 0x03, 0x11, 0x29, 0x15, 0x3F, 0x33, 0x09, 0x1F, 0x1D, 0x23, 0x33]
ke8=[0x38, 0x1E, 0x38, 0x2A, 0x0E, 0x16, 0x1E, 0x2A, 0x16, 0x2C, 0x1A, 0x1E, 0x3E, 0x10, 0x08, 0x28]
ke9=[0x27, 0x3D, 0x25, 0x3F, 0x2D, 0x29, 0x19, 0x21, 0x27, 0x39, 0x33, 0x05, 0x17, 0x13, 0x0D, 0x15]
ke10=[0x30, 0x1C, 0x28, 0x22, 0x24, 0x08, 0x22, 0x10, 0x00, 0x16, 0x10, 0x24, 0x0C, 0x1C, 0x1C, 0x06]
ke11=[0x25, 0x05, 0x1F, 0x2D, 0x27, 0x33, 0x19, 0x0B, 0x01, 0x0D, 0x21, 0x31, 0x15, 0x31, 0x3B, 0x17]
ke12=[0x16, 0x2E, 0x36, 0x10, 0x08, 0x28, 0x02, 0x20, 0x06, 0x00, 0x28, 0x0E, 0x14, 0x0A, 0x04, 0x22]
ke13=[0x35, 0x2D, 0x31, 0x17, 0x3B, 0x1D, 0x29, 0x03, 0x21, 0x0B, 0x0B, 0x3F, 0x05, 0x31, 0x11, 0x1D]
ke14=[0x3E, 0x0A, 0x2A, 0x02, 0x2A, 0x08, 0x24, 0x1E, 0x1E, 0x3A, 0x38, 0x1E, 0x2C, 0x2A, 0x1C, 0x3C]
ke15=[0x13, 0x01, 0x27, 0x39, 0x2F, 0x25, 0x1B, 0x09, 0x2D, 0x13, 0x11, 0x1D, 0x31, 0x0B, 0x37, 0x17]
ke16=[0x2E, 0x22, 0x24, 0x0E, 0x2A, 0x36, 0x00, 0x0E, 0x34, 0x2A, 0x32, 0x00, 0x14, 0x20, 0x14, 0x08]
ke17=[0x21, 0x1F, 0x17, 0x03, 0x27, 0x2B, 0x29, 0x01, 0x15, 0x1F, 0x1B, 0x05, 0x25, 0x39, 0x35, 0x23]
ke18=[0x20, 0x30, 0x32, 0x16, 0x32, 0x12, 0x06, 0x32, 0x3C, 0x1A, 0x16, 0x18, 0x30, 0x22, 0x24, 0x1E]
ke19=[0x11, 0x2B, 0x21, 0x05, 0x3F, 0x01, 0x25, 0x0B, 0x39, 0x13, 0x33, 0x09, 0x3F, 0x39, 0x35, 0x25]
>>> ke19=[0x11, 0x2B, 0x21, 0x05, 0x3F, 0x01, 0x25, 0x0B, 0x39, 0x13, 0x33, 0x09, 0x3F, 0x39, 0x35, 0x25]
>>> k2a(ke19)
'rPFf9bJl3tXj93ZJ'
0x03 从简化模型而来的修正
在 def r2xyzt(r=0x14,idx=0)函数中,增加了下述修正代码。源于A中每行从k中选出的三个坐标并不都是
从左到右依次充当x,y,z的角色,如果是,则不需要加入如下代码。
#------- ------- ------- ------- ------- ------- -------
if idx == 0:
pass #xyz=xyz
elif idx in [1,2,3,4,7,8,9,10,11]:
xyz = xyz[2] + xyz[0] + xyz[1]
else:
xyz = xyz[1] + xyz[2] + xyz[0]
#------- ------- ------- ------- ------- ------- -------
实际上x,y,z的赋值,依次为搜索A中每行第1次、第2次、第2次出现的位置决定的k值。
而各行开始搜索的位置并不都是从0开始的。在0x00的F5修正源码中,
loc_pKn_startPosRef局部变量指示了每行开始循环搜索的位置,
loc_pKn_startPosRef=loc_pKn_x+++1;每循环搜索完一行,其位置都会递增。
即实际各行开始循环搜索的位置是16*16矩阵A的对角线位置。
如A的第1行(从0行开始)
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
则K1由k0,k3,k4 索引mxyz空间得到,但由于该行从k1位置开始循环搜索,所以依次搜到的是k3,k4,k0,即x=k3,y=k4,z=k0,
所以K1=mxyz[k3][k4][k0],而不是修正前的的mxyz[k0][k3][k4]
同理,A的第15行(从0行开始)
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
则K1由k11,k12,k15 索引mxyz空间得到,但由于该行从k15位置开始循环搜索,所以依次搜到的是k15,k11,k12,即x=k15,y=k11,z=k12,
所以K1=mxyz[k15][k11][k12],而不是修正前的的mxyz[k11][k12][k15]
由于我们的kets2k函数是针对简化模型建立的,所以必须给予修正。
针对A的第1行。简化模型是 k0->k3->k4,由于x=k3,y=k4,z=k0,即得到x,y,z后,需修正为 z->x->y,这就有了
elif idx in [1,2,3,4,7,8,9,10,11]:
xyz = xyz[2] + xyz[0] + xyz[1]
同理,针对第15行,简化模型是k11->k12->k15,由于x=k15,y=k11,z=k12,即得到x,y,z后,需修正为y->z->x这就有了
else:
xyz = xyz[1] + xyz[2] + xyz[0]
#-----------------------
上述计算量还算比较大,本机执行r2xyzt得到K[i]解集树的时间2s内,K长为16,就需32s。
遍历求解k的过程kets2k则需要7s内,即完成依次求逆需要39s,19次需要741=39*19约13分钟。
上述执行过程中可以看到计算进度,就像现实版的爬楼梯,一个阶梯一个阶梯爬,每爬16级一层,要爬完19级还是要费点时间。
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
赞赏
他的文章
鸿蒙通识
23240
看原图