试运行一下,错误会提示wrong,IDA打开,shift+f12搜字符串wrong,找到关键函数sub_401090。F5反编译失败,某地址报错:call指令识别不了。
百度一手资料,两种可能; 1、IDA无法识别出正确的调用约定。 2、IDA无法识别出正确的参数个数。
看call调用的函数,发现只需要一个参数即可 ,所以是参数问题,选中call调用的函数,按y,修改参数为1个(去调后面的char)。F5一下,简单的异或。
tmp=[0x4D,0x53, 0x41, 0x57, 0x42, 0x7E, 0x46, 0x58, 0x5A, 0x3A,0x4A,0x3A, 0x60, 0x74, 0x51, 0x4A, 0x22, 0x4E, 0x40, 0x20,0x62, 0x70, 0x64, 0x64, 0x7D, 0x38, 0x67] flag=[0 for i in range(27)] for i in range(27): flag[i]=i^tmp[i] print(''.join(map(chr,flag))) #MRCTF{@_R3@1ly_E2_R3verse!}披着驱动皮的maze 主函数标准的键盘过滤函数。 重点放在IRP读函数,点进去发现一个函数sub_140001380。 再进入sub_140001380,发现是个地图题。上下左右需用键盘扫描码对应的字母代替。 md5加密就是flag。
IDA打开,一共三个函数,提示里说flag被藏起来了,函数看着挺正常的,就是一大串数据只传入了一部分,结合弹窗提示I never broke the encoding,考虑将所有数据传入,看最终加密后的结果。 X64dbg打开,修改机器码,传入的参数值。 运行就跑了出来。
go的逆向,IDA直接打开,找到main函数,看函数猜逻辑,直接明文比较
main函数base64,base64考换表base64,所以找换表函数 所以找到换表函数,写脚本换表。
B=[0x41,0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F] for i in range(10): v0=B[i] B[i]=B[19-i] B[19-i]=v0 print(''.join(map(chr,B))) #TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/换表base64解密。wctf2020{Base64_is_the_start_of_reverse}
开始看着很乱,主要是自己心里没有这样的模型。 整体分四部分。
考点:将字符转成整型数处理:移位堆叠。
from z3 import * x,y,z,w=BitVecs('x y z w',64) s=Solver() s.add((~x)&z==1176889593874) s.add(((z&~x)|(x&y)|(z&(~y))|(x&(~y)))^w==4483974543195470111) s.add(((z&~y)&x|z&((x&y)|y&~x|~(y|x)))==577031497978884115) s.add(((z&~x)|(x&y)|(z&~y)|(x&~y))==4483974544037412639) s.add(((z&(~x)) | (x&y) | y & z) == (((~x)& z)|864693332579200012)) s.check() m = s.model() for i in m: print("%s = 0x%x"%(i,m[i].as_long())) #w = 0x32310600 #z = 0x8020717153e3013 #y = 0xc00020130082c0c #x = 0x3e3a460533286f0d Dst = 'i_will_check_is_debug_or_noi_wil' flag=[0x3E,0x3A,0x46,0x05,0x33,0x28,0x6F,0x0D,0x8C,0x00,0x8A,0x09,0x78,0x49,0x2C,0xAC,0x08,0x02,0x07,0x17,0x15,0x3E,0x30,0x13,0x32,0x31,0x06] s='' for i in range(len(flag)): s+=chr(ord(Dst[i]) ^ flag[i]) print(s) #We1l_D0näeéb' _ólgebra_am_i求出来的flag有乱码,当时题目提示了e!P0or_a。所以最终We1l_D0ne!P0or_algebra_am_i
每个字符的明文比较,找一张纸,写下来得到flag
流程; 1.取输入字符的前4个(flag)作为秘钥 2.将输入字符和秘钥(flag+12个0)xxtea加密 3.加密后的密文变换位置 4.关系较复杂的异或
#逆向求xxtea加密后的密文 data0 = "CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA"#为提取出来的v29,v29+1,v30,v31 data = [] for i in range(0,len(data0),2): data.append(int(data0[i]+data0[i+1],16))#每两位为整体,将16进制转换为10进制 print(data) for i in range(len(data)-1,-1,-1): for j in range(i//3): data[i] ^= data[j] #进行的异或操作 print(data) biao = [2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]#置换表 shuju = [0 for i in range(24)] for i in range(24): shuju[biao[i]] = data[i]#将其按照一定顺序置换 s=''.join(hex(i)[2:] for i in shuju) print(shuju) print(s) print(len(shuju))小端存储 密文:bca5ce40f4b2b2e7a9129d12ae10c85b3dd7061ddc70f8dc key:flag
xxtea算法识别: tea 2个异或 xtea 2个异或+&3 xxtea 6个异或+&3
//xxtea脚本解密 #include <stdio.h> #include <stdint.h> #include<windows.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea(uint32_t *v, int n, uint32_t const key[4]) { uint32_t y, z, sum; unsigned p, rounds, e; if (n > 1) /* Coding Part */ { rounds = 6 + 52 / n; sum = 0; z = v[n - 1]; do { sum += DELTA; e = (sum >> 2) & 3; for (p = 0; p < n - 1; p++) { y = v[p + 1]; z = v[p] += MX; } y = v[0]; z = v[n - 1] += MX; } while (--rounds); } else if (n < -1) /* Decoding Part */ { n = -n; rounds = 6 + 52 / n; sum = rounds * DELTA; y = v[0]; do { e = (sum >> 2) & 3; for (p = n - 1; p > 0; p--) { z = v[p - 1]; y = v[p] -= MX; } z = v[n - 1]; y = v[0] -= MX; sum -= DELTA; } while (--rounds); } } int main() { //03e0164dd30553aa // uint32_t a[2] = { (unsigned int)0xd2cfdad7, 0x9ac8d5d4 }; uint32_t v[6] = { (unsigned int)0x40cea5bc, (unsigned int)0xe7b2b2f4,(unsigned int)0x129d12a9,(unsigned int)0x5bc810ae,(unsigned int)0x1d06d73d,(unsigned int)0xdcf870dc }; uint32_t const k[4] = { (unsigned int)0x67616c66, (unsigned int)0x0, (unsigned int)0X0, (unsigned int)0x0 }; int n = 6; //n的绝对值表示v的长度,取正表示加密,取负表示解密 // v为要加密的数据是两个32位无符号整数 // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位 //printf("加密前原始数据:%x %x\n", v[0], v[1]); btea(v, -n, k); printf("加密后的数据:%x %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5]); //btea(v, -n, k); //printf("解密后的数据:%x %x\n", v[0], v[1]); system("pause"); }小端存储组合 666c61677b4358585f616e645f2b2b7465617d flag{CXX_and_++tea} 大家都是整数还比较好理解,有整数有字符就易理解混。 字符总要转成数字来运算。 前16位字符有的是ascii值有的是它本身,除前16位的其他字符是ascii码 ascii码还是好转的,前16位字符若想转成本身就需要下面的脚本 字符串里的16进制的字符转成与它长相一样的10进制整数
result = 'CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA' res = [] for x in range(0,len(result),2): res.append(int(('0x'+result[x]+result[x+1]), 16)) print(res)