放入 JEB,截两段重要源码
这个 ab.a 算法其实有多解,其实本题最后应该有4个解
K^ -> X k~ -> x @S -> F M\ -> Z `s -> f m| -> z L_ -> Y
附 python 编解码
jni 有3个平台可供选择分析,我选择了 IDA 相容性较好的 armeabi-v7a 版本
jni 部分有数种反调试手段,但是都可以用比较原始的方法去掉
需要使用调试来判断2个变种加密算法的修改细节,本文最后一部分会附上 diff,因为题目进行中公开了用户输入的前8位 kxuectf{
和末位 }
,本文将在给出提示的前提下提供解法步骤
set_key 位移部分不知道有bug还是啥,和标准不大一样,原型代码
RC6 部分赛后 poyoten 发现应该是这个实现 ,我为了用 go 快速枚举,我是在 go-rc6 这个实现上修改的
this.button.setOnClickListener(new View$OnClickListener() {
public void onClick(View v) {
// 点击事件,组装 ab.a(下面的算法)、ba.a(一个替换算法)、ca.a(base64)
// 传入 jni 的 check 函数
String v2 = uv.this.editText.getText().toString().trim();
if(ua.check(ab.a(v2) + ba.a(v2) + ca.a(v2)) == 1) {
bc.showresult(uv.this.tv, true);
}
else {
bc.showresult(uv.this.tv, false);
}
}
});
// 上面的 ab.a 算法
public static String encrypt(String input) {
String v3 = "";
int v2;
for(v2 = 0; v2 < input.length(); ++v2) {
int v0 = input.charAt(v2);
if(v0 < 97 || v0 > 109) {
if(v0 >= 65 && v0 <= 77) {
v3 = String.valueOf(v3) + (((char)(v0 + 13)));
goto label_21;
}
if(v0 >= 110 && v0 <= 122) {
v3 = String.valueOf(v3) + (((char)(v0 - 13)));
goto label_21;
}
if(v0 >= 78 && v0 <= 90) {
v3 = String.valueOf(v3) + (((char)(v0 - 13)));
goto label_21;
}
if(v0 >= 48 && v0 <= 57) {
v3 = String.valueOf(v3) + (((char)(v0 ^ 7)));
goto label_21;
}
v3 = String.valueOf(v3) + (((char)(v0 ^ 6)));
}
else {
v3 = String.valueOf(v3) + (((char)(v0 + 13)));
}
label_21:
}
return v3;
}
from collections import defaultdict
def aba_(d):
if 65 <= d <= 77:
return chr(d + 13)
elif 110 <= d <= 122:
return chr(d - 13)
elif 78 <= d <= 90:
return chr(d - 13)
elif 48 <= d <= 57:
return chr(d ^ 7)
elif 97 <= d <= 109:
return chr(d + 13)
return chr(d ^ 6)
def aba_enc(s):
r = ""
for c in s:
r += aba_(ord(c))
return r
def aba_dec(s):
dt = defaultdict(str)
for i in xrange(0x20, 0x7F):
dt[aba_(i)] += chr(i)
r = ""
for c in s:
t = dt[c]
if len(t) == 1:
r += t
else:
r += '[' + t + ']'
return r
--- Des.cpp 2017-06-22 21:29:47.000000000 +0800
+++ Des2.cpp 2017-06-25 12:19:36.000000000 +0800
@@ -6,7 +6,7 @@
*/
//////////////////////////////////////////////////////////////////////////
-#include "memory.h"
+#include <string.h>
#include "Des.h"
//////////////////////////////////////////////////////////////////////////
@@ -163,7 +163,13 @@
Xor(Ri, Li, 32);
memcpy(Li, tmp, 32);
}
+ memcpy(tmp, M, 32);
+ memcpy(M, M + 32, 32);
+ memcpy(M + 32, tmp, 32);
}else{
+ memcpy(tmp, M, 32);
+ memcpy(M, M + 32, 32);
+ memcpy(M + 32, tmp, 32);
for(int i=15; i>=0; --i) {
memcpy(tmp, Li, 32);
F_func(Li, (*pSubKey)[i]);
@@ -179,10 +185,23 @@
static bool K[64], *KL=&K[0], *KR=&K[28];
ByteToBit(K, Key, 64);
Transform(K, K, PC1_Table, 56);
+ static bool KK[120], *K1=&KK[0], *K2=&KK[60];
+ memcpy(K1, K, 28); memcpy(K1 + 28, K, 28);
+ memcpy(K2, K + 28, 28); memcpy(K2 + 28, K + 28, 28);
+
+ int loop = 0;
for(int i=0; i<16; ++i) {
- RotateL(KL, 28, LOOP_Table[i]);
- RotateL(KR, 28, LOOP_Table[i]);
- Transform((*pSubKey)[i], K, PC2_Table, 48);
+ loop += LOOP_Table[i];
+ for (int j=0; j<48; ++j) {
+ int k = PC2_Table[j];
+ bool r;
+ if (k < 28) {
+ r = K1[loop + k - 1];
+ } else {
+ r = K1[32 + loop + k - 1];
+ }
+ SubKey[0][i][j] = r;
+ }
}
}
void F_func(bool In[32], const bool Ki[48])
@@ -220,14 +239,18 @@
}
void ByteToBit(bool *Out, const char *In, int bits)
{
+ int t = bits - 1;
+ if (t > 7) t = 7;
for(int i=0; i<bits; ++i)
- Out[i] = (In[i>>3]>>(i&7)) & 1;
+ Out[i] = (In[i>>3]>>(t-i%8))&1;
}
void BitToByte(char *Out, const bool *In, int bits)
{
+ int t = bits - 1;
+ if (t > 7) t = 7;
memset(Out, 0, bits>>3);
for(int i=0; i<bits; ++i)
- Out[i>>3] |= In[i]<<(i&7);
+ Out[i>>3] |= In[i]<<(t-i%8);
}
//////////////////////////////////////////////////////////////////////////
// Code ends at Line 231
// Package rc6 implements the RC6 cipher
/*
For more information, please see:
https://en.wikipedia.org/wiki/RC6
http://www.emc.com/emc-plus/rsa-labs/historical/rc6-block-cipher.htm
*/
package rc6
import (
"crypto/cipher"
"strconv"
)
const (
rounds = 20
roundKeys = 2*rounds + 4
keyWords = 4
)
type rc6cipher struct {
rk [roundKeys]uint32
L [4]uint32
}
func rotl32(k uint32, rot uint32) uint32 {
return (k << rot) | (k >> (32 - rot))
}
func rotr32(k uint32, rot uint32) uint32 {
return (k >> rot) | (k << (32 - rot))
}
type KeySizeError int
func (k KeySizeError) Error() string { return "rc6: invalid key size " + strconv.Itoa(int(k)) }
// New returns a cipher.Block implementing RC6. The key argument must be 16 bytes.
func New(key []byte) (cipher.Block, error) {
if l := len(key); l != 16 {
return nil, KeySizeError(l)
}
c := &rc6cipher{}
for i := 0; i < keyWords; i++ {
c.L[i] = getUint32(key)
key = key[4:]
}
return c, nil
}
func (c *rc6cipher) setrk() {
copy(c.rk[:], skeytable)
var A uint32
var B uint32
var i, j int
for k := 0; k < 3*roundKeys; k++ {
c.rk[i] = rotl32(c.rk[i]+(A+B), 3)
A = c.rk[i]
c.L[j] = rotl32(c.L[j]+(A+B), (A+B)&31)
B = c.L[j]
i = (i + 1) % roundKeys
j = (j + 1) % keyWords
}
}
func (c *rc6cipher) BlockSize() int { return 16 }
func (c *rc6cipher) Encrypt(dst, src []byte) {
A := getUint32X(src)
B := getUint32X(src[4:])
C := getUint32X(src[8:])
D := getUint32X(src[12:])
c.setrk()
B = B + c.rk[0]
D = D + c.rk[1]
for i := 1; i <= rounds; i++ {
t := rotl32(B*(2*B+1), 5)
u := rotl32(D*(2*D+1), 5)
A = rotl32((A^t), u&31) + c.rk[2*i]
C = rotl32((C^u), t&31) + c.rk[2*i+1]
A, B, C, D = B, C, D, A
}
A = A + c.rk[2*rounds+2]
C = C + c.rk[2*rounds+3]
putUint32X(dst, A)
putUint32X(dst[4:], B)
putUint32X(dst[8:], C)
putUint32X(dst[12:], D)
}
func (c *rc6cipher) Decrypt(dst, src []byte) {
A := getUint32X(src)
B := getUint32X(src[4:])
C := getUint32X(src[8:])
D := getUint32X(src[12:])
c.setrk()
C = C - c.rk[2*rounds+3]
A = A - c.rk[2*rounds+2]
for i := rounds; i >= 1; i-- {
A, B, C, D = D, A, B, C
u := rotl32(D*(2*D+1), 5)
t := rotl32(B*(2*B+1), 5)
C = rotr32((C-c.rk[2*i+1]), t&31) ^ u
A = rotr32((A-c.rk[2*i]), u&31) ^ t
}
D = D - c.rk[1]
B = B - c.rk[0]
putUint32X(dst, A)
putUint32X(dst[4:], B)
putUint32X(dst[8:], C)
putUint32X(dst[12:], D)
}
// avoid pulling in encoding/binary
func getUint32(b []byte) uint32 {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
func getUint32X(b []byte) uint32 {
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
func putUint32(b []byte, v uint32) {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
}
func putUint32X(b []byte, v uint32) {
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
// skeytable computed from
/*
Pw = uint32(0xb7e15163)
Qw = uint32(0x9e3779b9)
T = 2*(R+2);
S[0] = Pw;
for (i = 1 ; i < T ; i++) {
S[i] = S[i-1] + Qw;
}
*/
var skeytable = []uint32{
0xb7e15163, 0x19a9d7aa, 0x7b725df1, 0xdd3ae438, 0x3f036a7f, 0xa0cbf0c6, 0x294770d, 0x645cfd54,
0xc625839b, 0x27ee09e2, 0x89b69029, 0xeb7f1670, 0x4d479cb7, 0xaf1022fe, 0x10d8a945, 0x72a12f8c,
0xd469b5d3, 0x36323c1a, 0x97fac261, 0xf9c348a8, 0x5b8bceef, 0xbd545536, 0x1f1cdb7d, 0x80e561c4,
0xe2ade80b, 0x44766e52, 0xa63ef499, 0x8077ae0, 0x69d00127, 0xcb98876e, 0x2d610db5, 0x8f2993fc,
0xf0f21a43, 0x52baa08a, 0xb48326d1, 0x164bad18, 0x7814335f, 0xd9dcb9a6, 0x3ba53fed, 0x9d6dc634,
0xff364c7b, 0x60fed2c2, 0xc2c75909, 0x248fdf50,
}
K^ -> X k~ -> x @S -> F M\ -> Z `s -> f m| -> z L_ -> Y
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)