Reverse
萌新第一篇博客,如有错误请多指正
这次本同校的队伍打爆了,争取明年能进决赛吧
asm_re
打开是一段ida里复制出来的汇编,但是把源文件的十六进制也复制出来了。

将十六进制写进新的文件,选择arm小端序,ida反编译


能看出对每一个字符ch做了((80 * ch + 20) ^ 0x4D) + 30的操作,解密即可
1 |
|
androidso_re
这apk根本跑不起来,不然谁还静态做啊

密文和加密方式已知,需要获取密钥和偏移,都在so中生成

iv先对F2IjBOh1mRW=进行简单的变换,然后base64解码得到

密钥先对”TFSecret_Key” rc4加密,然后异或前8位获得
最后解密即可
1 | import java.nio.charset.StandardCharsets; |
rust_baby
这段先将输入的字符串8bytes一组送入加密函数中,加密完后对每一位异或0x33

加密函数大致逻辑为将输入的两个64位key转化为小端存储的字节,然后进行加减操作加密,还原成c代码如下
1 | void someenc(char *input, unsigned __int64 key, unsigned __int64 num) |
对该加密函数动调可以发现,传入的第三个参数为依次为1,1,4,5,1,4,1,9,1,9,8,1,0,且对input赋值时可以发现keyarr[2 * i]&7和2 * i相等,2*i+1和v8&7相等。
下硬件断点跟踪,发现对加密过后的字符串和一个数组进行了异或,动调取出数组的所有值

最后进行了一次base64,和密文进行比较

exp
1 |
|
gdb_debug
一堆随机数的操作,但是没有种子,种子and了一个0xF0000000,最多只有16种情况,直接爆破种子就行。注意windows和linux随机数生成不同,要在linux上跑
1 |
|
whereThel1b
随便输入一个格式正确的flag,发现加密后前面一段正确

在so中发现了base64encode,猜测对输入做了三个字符为一组的加密,直接爆破。flag有两种格式,一种类似flag{1234567890123456789012345678901234},长度40;另一种flag{7f9a2d3c-07de-11ef-be5e-cf1e88674c0b}长度42,都试一遍

1 | import whereThel1b |
GoReverse
这题到比赛结束我都不知道密文到底在哪,看了wp才发现原来要连远端……
程序分析
通过字符串定位出主体部分。程序主体逻辑比较清晰,先打开flag文件读取flag,然后依次对flag依次进行逐位异或、魔改xxtea、sm4 CTR加密、AES256 CBC加密、base32最后输出

程序中有两处反调试,需要先patch掉
main函数中的反调试较为明显

另一段在0x0438E28,也就是在调用main_main函数的runtime_main函数中,动调的时候发现执行这个call之后程序就退出了,nop掉之后程序正常运行。(尚未知道原理,请大佬们多指教)

异或部分将flag与”D7BJLsOk9@f&1dWIn53IDlJqUS6$^WhkAk2kk*2GaqmLwiLX^bGGE$&dmqR^g5bL3lCA5^HGK$9qo5T@Bwom9vEXya0HAV3LrWW”异或

xxtea有两处魔改,DELTA改为0x7FAB4CAD,MX对运算顺序进行了一些改变,即
1 |


sm4部分ida反编译不全,需要看汇编,Go CTR模式的加密可以参照https://pkg.go.dev/crypto/cipher#example-NewCTR
对照源码可知该call github_com_tjfoc_gmsm_sm4_NewCipher对应block, err := aes.NewCipher(key),则key为pg5g#k6Qo3L&1EzT

然后产生了16bytes的随机数,作为sm4 CTR mode的iv


call crypto_cipher_NewCTR对应源码的stream := cipher.NewCTR(block, iv)

call rdx对应stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

注意此处的sm4 CTR模式将原来的iv拼接到了加密之后的结果,所以最终sm4的结果是随机生成的16字节iv+加密过后的结果
AES同样对照源码动调出key和iv,其中key为dPGWgcLpqmxw3uOXhKpKV009Cql@@XE6,iv为key的前16位

最后base32输出

逆向过程
解密base32和AES,根据对sm4的分析可知,解密过后的前16字节即为sm4随机生成的16字节iv
1 | from Crypto.Cipher import AES |
将iv放到cyberchef里sm4加密,根据flag长度为40或42可知counter还需要分别+1和+2,总共3*16bytes

将sm4加密过后的数据与AES解密的16位以后的数据异或
1 | ctr=bytes.fromhex('36 f6 50 d4 2e ea c3 78 73 cb 34 97 95 17 8e e4 af 11 e8 ed 25 cb 8d c4 5f fe fa 7c dd a0 4c 2c f5 45 f5 83 2b ed 6b 85 90 fc fa 93 82 5f a7 69 11 ba e2 41 45 1c e9 f6 ea 51 52 63 f5 41 5b 29') |
最后xxtea并异或一次
1 |
|
