原创 2022 KCTF 看雪学苑
出题团队简介
赛题设计思路
题目描述
帮小学小朋友看奥数的时候看到的,觉得很有意思就出题了,然后加了一些回忆杀在里面(砍传奇啊)
用 1 到 9 组成一个九位数,//每个数字都用了一次
使得这个数的第一位能被 1 整除,
前两位组成的两位数能被 2 整除,前三位组成的三位数能被 3 整除,
以此类推,一直到整个九位数能被 9 整除。
381654729 是唯一一个满足要求的数!
赛题解析
本赛题解析由看雪论坛 htg 给出:
工具:IDA
分析步骤:先简略看看程序运行情况
resultA = 0;
if ( lenSN )
{
v7 = Arglist;
do
{
v5 ^= *v7;
--v6;
++v7;
v8 = 8;
do
{
v9 = 2 * v5;
v10 = v9 ^ 7;
if ( v9 >= 0 )
v10 = v9;
v5 = v10;
--v8;
}
while ( v8 );
}
while ( v6 );
lenSN = lenSNcopy;
resultA = v10; // resultA是输出的结果
}
initArrayA(); // 构造:dword_EB5B20 数组。这个是全局变量,与用户输入无关
v11 = -1;
for ( i = 0; i < lenSN; ++i )
v11 = arrayA[(unsigned __int8)(v11 ^ Arglist[i])] ^ (v11 >> 8);// 0x0AD1F89A
signA = ~v11; // signA == 0xF52E0765
stringToInt((int)Arglist, lenSN); // 对用户输入的字符串进行转换:将字符转换成数值,'0123456789ABCDEF'-->0123456789ABCDEF
v13 = resultA;
v36 = 1;
v35 = resultA + 1;
v14 = v35;
do
{
v15 = v13;
for ( j = 1; j < 0xC8; ++j )
{
if ( (v15 & 1) != 0 )
v15 = 3 * v15 + 1;
else
v15 >>= 1;
arrayB[j] = v15;
}
++v13;
}
while ( v13 < v14 ); // 只循环一遍,构造了v33表
signB = arrayB[0xC6] | arrayB[0xC5] | arrayB[0xC4];// 1^2^4=7
lenSNcopy2 = lenSNcopy;
if ( signB != (Arglist[2] ^ Arglist[1] ^ Arglist[0]) )// 第一个判断:前三位异或之后结果为7
midBytes = signB + 2;
restBytes = lenSNcopy2 - midBytes - 7;
if ( Arglist[3] != 0x14 )
if ( Arglist[4] != 0xC )
if ( Arglist[5] != 0x1D )
if ( Arglist[6] != 0xF )
v21 = 0;
lenSNcopy = 0;
if ( midBytes > 0 )
{
v22 = 1;
do
{
v23 = Arglist[v22 + 6] + 10 * v37; // 十进制算法。十进制数值字符串转换成十进制数值??
v24 = v23 - 0x37373737; // 7777
if ( v23 <= 0x4B435445 ) // KCTE
v24 = v23;
v37 = v24;
if ( v24 % v36 ) // 不能跳进去:需要被整除。
goto LABEL_50;
v21 = lenSNcopy + 1;
v22 = v36 + 1;
lenSNcopy = v21;
++v36;
}
while ( v21 < midBytes );
}
v25 = midBytes - 1;
if ( midBytes - 1 > 0 ) // 冒泡排序算法:Arglist【7:7+signBsubTwo-1】即对从7开始的signBsubTwo个数进行排序
{
v26 = midBytes - 1;
do
{
v27 = 0;
if ( v25 > 0 )
{
do
{
v28 = Arglist[v27 + 7];
v29 = Arglist[v27 + 8];
if ( v28 > v29 )
{
Arglist[v27 + 7] = v29;
Arglist[v27 + 8] = v28;
}
++v27;
}
while ( v27 < v25 );
v3 = 0;
}
--v25;
--v26;
}
while ( v26 );
}
stringToInt((int)a1234567890Abcd, midBytes); // 1234567890_ABCDEFGHIJKLMNOPQRSTUVWXYZ转换成1234567890,0x28,abcdef,0x16,0x17,0x18,......,0x23
v30 = 0;
if ( midBytes > 0 )
{
while ( a1234567890Abcd[v30] == Arglist[v30 + 7] )// 第六个判断:必须满足
{
if ( ++v30 >= midBytes ) // 必须跳出去:重复次数是 signBsubTwo
goto LABEL_41;
}
goto LABEL_49;
}
Arglist7laterTrans = &Arglist[midBytes + 7];
sub_EB10E1((int)Arglist7laterTrans, restBytes);
if ( restBytes <= 0 ) // 第七个判断
if ( restBytes <= 0 ) // 第七个判断
{
LABEL_45:
sub_EB100C("\n你想吃猪肉,到猪洞七层准备打个白野猪.白野猪死后尸体尽然掉出一把 屠龙 .");
if ( signA == 0xF52E0765 ) // 第八个判断
……………………
}
else
{ // 这是一个大坑,没必要进入
while ( ((unsigned __int8)asc_EB55C0[v3] ^ (unsigned __int8)Arglist7laterTrans[v3]) == asc_EB3DC8[v3] )
{
if ( ++v3 >= restBytes )
goto LABEL_45;
………………
}
}
import os
#从IDA里拷贝出来【如有时间,再考虑具体算法】
#初始化大数组
def InitArrayA():
#先直接从 IDA 里拷贝。
tmpArray = [ 0x00000000,0x09073096,0x120E612C,0x1B0951BA,0xFF6DC419,0xF66AF48F,0xED63A535,0xE46495A3,0xFEDB8832,0xF7DCB8A4,0xECD5E91E,0xE5D2D988,0x01B64C2B,0x08B17CBD,0x13B82D07,0x1ABF1D91,0xFDB71064,0xF4B020F2,0xEFB97148,0xE6BE41DE,0x02DAD47D,0x0BDDE4EB,0x10D4B551,0x19D385C7,0x036C9856,0x0A6BA8C0,0x1162F97A,0x1865C9EC,0xFC015C4F,0xF5066CD9,0xEE0F3D63,0xE7080DF5,0xFB6E20C8,0xF269105E,0xE96041E4,0xE0677172,0x0403E4D1,0x0D04D447,0x160D85FD,0x1F0AB56B,0x05B5A8FA,0x0CB2986C,0x17BBC9D6,0x1EBCF940,0xFAD86CE3,0xF3DF5C75,0xE8D60DCF,0xE1D13D59,0x06D930AC,0x0FDE003A,0x14D75180,0x1DD06116,0xF9B4F4B5,0xF0B3C423,0xEBBA9599,0xE2BDA50F,0xF802B89E,0xF1058808,0xEA0CD9B2,0xE30BE924,0x076F7C87,0x0E684C11,0x15611DAB,0x1C662D3D,0xF6DC4190,0xFFDB7106,0xE4D220BC,0xEDD5102A,0x09B18589,0x00B6B51F,0x1BBFE4A5,0x12B8D433,0x0807C9A2,0x0100F934,0x1A09A88E,0x130E9818,0xF76A0DBB,0xFE6D3D2D,0xE5646C97,0xEC635C01,0x0B6B51F4,0x026C6162,0x196530D8,0x1062004E,0xF40695ED,0xFD01A57B,0xE608F4C1,0xEF0FC457,0xF5B0D9C6,0xFCB7E950,0xE7BEB8EA,0xEEB9887C,0x0ADD1DDF,0x03DA2D49,0x18D37CF3,0x11D44C65,0x0DB26158,0x04B551CE,0x1FBC0074,0x16BB30E2,0xF2DFA541,0xFBD895D7,0xE0D1C46D,0xE9D6F4FB,0xF369E96A,0xFA6ED9FC,0xE1678846,0xE860B8D0,0x0C042D73,0x05031DE5,0x1E0A4C5F,0x170D7CC9,0xF005713C,0xF90241AA,0xE20B1010,0xEB0C2086,0x0F68B525,0x066F85B3,0x1D66D409,0x1461E49F,0x0EDEF90E,0x07D9C998,0x1CD09822,0x15D7A8B4,0xF1B33D17,0xF8B40D81,0xE3BD5C3B,0xEABA6CAD,0xEDB88320,0xE4BFB3B6,0xFFB6E20C,0xF6B1D29A,0x12D54739,0x1BD277AF,0x00DB2615,0x09DC1683,0x13630B12,0x1A643B84,0x016D6A3E,0x086A5AA8,0xEC0ECF0B,0xE509FF9D,0xFE00AE27,0xF7079EB1,0x100F9344,0x1908A3D2,0x0201F268,0x0B06C2FE,0xEF62575D,0xE66567CB,0xFD6C3671,0xF46B06E7,0xEED41B76,0xE7D32BE0,0xFCDA7A5A,0xF5DD4ACC,0x11B9DF6F,0x18BEEFF9,0x03B7BE43,0x0AB08ED5,0x16D6A3E8,0x1FD1937E,0x04D8C2C4,0x0DDFF252,0xE9BB67F1,0xE0BC5767,0xFBB506DD,0xF2B2364B,0xE80D2BDA,0xE10A1B4C,0xFA034AF6,0xF3047A60,0x1760EFC3,0x1E67DF55,0x056E8EEF,0x0C69BE79,0xEB61B38C,0xE266831A,0xF96FD2A0,0xF068E236,0x140C7795,0x1D0B4703,0x060216B9,0x0F05262F,0x15BA3BBE,0x1CBD0B28,0x07B45A92,0x0EB36A04,0xEAD7FFA7,0xE3D0CF31,0xF8D99E8B,0xF1DEAE1D,0x1B64C2B0,0x1263F226,0x096AA39C,0x006D930A,0xE40906A9,0xED0E363F,0xF6076785,0xFF005713,0xE5BF4A82,0xECB87A14,0xF7B12BAE,0xFEB61B38,0x1AD28E9B,0x13D5BE0D,0x08DCEFB7,0x01DBDF21,0xE6D3D2D4,0xEFD4E242,0xF4DDB3F8,0xFDDA836E,0x19BE16CD,0x10B9265B,0x0BB077E1,0x02B74777,0x18085AE6,0x110F6A70,0x0A063BCA,0x03010B5C,0xE7659EFF,0xEE62AE69,0xF56BFFD3,0xFC6CCF45,0xE00AE278,0xE90DD2EE,0xF2048354,0xFB03B3C2,0x1F672661,0x166016F7,0x0D69474D,0x046E77DB,0x1ED16A4A,0x17D65ADC,0x0CDF0B66,0x05D83BF0,0xE1BCAE53,0xE8BB9EC5,0xF3B2CF7F,0xFAB5FFE9,0x1DBDF21C,0x14BAC28A,0x0FB39330,0x06B4A3A6,0xE2D03605,0xEBD70693,0xF0DE5729,0xF9D967BF,0xE3667A2E,0xEA614AB8,0xF1681B02,0xF86F2B94,0x1C0BBE37,0x150C8EA1,0x0E05DF1B,0x0702EF8D ]
return tmpArray
#根据输入的SN,获取resultA
def CalcResultA(SN):
initByte = 0x00
tmpByteA = 0x00
tmpByteB = 0x00
for ch in SN:
#print("ch:{}".format(ch))
initByte ^= ord(ch)
for i in range(8):
tmpByteA = (2 * initByte) & 0xFF
#print("tmpByteA:{}".format(hex(tmpByteA)[2:]))
tmpByteB = tmpByteA ^ 7
if tmpByteA < 0x80 : #对应于 正数
tmpByteB = tmpByteA
initByte = tmpByteB
#print("tmpByteB:{}".format(hex(tmpByteB)[2:]))
return tmpByteB
#对输入的字符进行处理:'0'->0 '9'--->9 'a'---->10 ....
def String2IntList(SN):
returnList =[]
for ch in SN:
tmpBase = 0x30
if ord(ch)>=0x3A:
tmpBase = 0x37
returnList.append(ord(ch)-tmpBase)
return returnList
#搜索函数
def DoSearch(SN):
global arrayA
#print("当前的SN:{}\n 长度:{}".format(SN,len(SN)))
#os.system("pause")
#TODO:已经构造完成:开始进行判断
resultA = CalcResultA(SN)
#print("resultA:{}".format(hex(resultA)))
signA = 0xFFFFFFFF
lenSN = len(SN)
for ch in SN:
tmpIndex = (signA ^ ord(ch)) & 0xFF
tmpValue = arrayA[tmpIndex]
#print("tmpIndex:{}".format(hex(tmpIndex)))
#SAR算数移位
if signA >= 0x80000000:
#负数,右移之后,要在最高位带上FF
signA = ((signA >> 8)|0xFF000000) ^ tmpValue
else:
signA = (signA >> 8) ^ tmpValue
#print("signA:{}".format(hex(signA)))
signA = signA ^ 0xFFFFFFFF #取反 就是 异或 全1
if signA != 0xF52E0765:
#print("signA: {} != 0xF52E0765".format(hex(signA)))
#os.system("pause")
return None
#输出一个结果:
print("找到SN:{}".format(SN))
os.system("pause")
#主函数入口
def main():
#序列号
SN = ""
#分析算法结构
'''
01 3个字符
02 4个固定字符,即为 KCTF
03 不大于9个字符,且必须为数值1-9
04 没有字符,题目埋了一个坑
'''
#第3部分:9个字符。
part3Code = "381654729"
for a in usedList:
for b in usedList:
for c in usedList:
SN = chr(a) + chr(b) + chr(c)
#对SN:前3个字符进行计算,以确保其相互异或,结果为 7
tmpIntLst = String2IntList(SN)
if tmpIntLst[0] ^ tmpIntLst[1] ^ tmpIntLst[2] != 0x7:
continue
#print("找到SN:{}".format(SN))
#前单个字符要进行sign换算
SN = SN +'KCTF' + part3Code
#调用另外一个命令,继续构造
DoSearch(SN)
if __name__ == "__main__":
global arrayA
arrayA=[]
usedList = list(range(0x21,0x7E,1))
print("usedCharList:\n{}".format([hex(x)[2:].upper() for x in usedList]))
arrayA = InitArrayA()
#main()
'''
以下是辅助代码
constStr = '1234567890_ABCDEFGHIJKLMNOPQRSTUVWXYZ'
constIntList = String2IntList(constStr)
print("constIntList")
print(','.join(hex(x)[2:] for x in constIntList))
print('测试最后的部分')
asc_EB55C0 = '我,韩立,作为一名光荣的程序员,月亮不睡我不睡,太阳没起我就起,夜以继日,终于把肉身修炼腐朽了...然后,穿越了...'
asc_EB3DC8 = '我辈读书人一生所求不过四事:为天地立心,为生民立命,为往圣继绝学,为万世开太平.'
asc_EB55C0_to_gbk = asc_EB55C0.encode("gbk")
asc_EB3DC8_to_gbk = asc_EB3DC8.encode("gbk")
returnRestList = []
for i in range(20):
returnRestList.append(asc_EB55C0_to_gbk[i]^asc_EB3DC8_to_gbk[i])
print("returnRestList")
print(','.join(hex(x)[2:] for x in returnRestList))
#0,0,9d,8,1d,0,68,c5,1f,3c,1c,11,1b,41,8,2,7e,11,7a,62
'''
###找到满足要求的数值:9
import itertools
from itertools import permutations
'''
num_list = [1,2,3,4,5,6,7,8,9]
num_list = [1,2,3,4,5,6,7,8]
num_list = [1,2,3,4,5,6,7] #none
num_list = [1,2,3,4,5,6]
num_list = [1,2,3,4,5] #none
num_list = [1,2,3,4]#none
num_list = [1,2,3]
num_list = [1,2]
num_list = [1]
'''
def permute(nums):
result = []
for i in permutations(nums,len(nums)):
#print(list(i))
tmp = "".join(str(x) for x in list(i))
#print("tmp:{}".format(tmp))
result.append(tmp)
return result
def main():
#print('\n')
#print(permute(num_list))
for i in range(9):
num_list = []
##生成 num_list
for j in range(i+1):
num_list.append(j+1)
print("#"*50+"\n"+"num_list:{}".format(num_list))
##num_list 生成 permute(num_list) 用作候选
lst = permute(num_list)
##开始查找
cur = len(num_list)
for k in lst:
for m in range(cur):
n = m + 1
x = int(k[:n])
if x % n != 0:
break
if n == cur:
print("found:\t{}".format(k))
if __name__ == "__main__":
print("开始查找")
main()
print("#"*50)
'''
found:381654729
found:38165472
found:123654
found:321654
found:123
found:321
found:12
found:1
'''
第三题《石像病毒》还在火热进行中,
球分享
球点赞
球在看