首页
社区
课程
招聘
[原创]看雪CTF2017第12题
2017-6-24 17:59 3919

[原创]看雪CTF2017第12题

2017-6-24 17:59
3919

1. dex处理逻辑


encode1是base64, encode2和encode3比较简单, 略过


sn = encode3(sn) + encode2(sn) + encode1(sn)

public class Main extends ac {
		...
    protected void onCreate() {
        super.onCreate();
				...
				// 这个不懂为什么没生效, 生效的是基类那个
        this.button.setOnClickListener(new View$OnClickListener() {
            public void onClick(View v) {
                String v2 = Main.this.editText.getText().toString().trim();
                if(ua.check(ca.encode1(v2) + ba.encode2(v2) + ab.encode3(v2)) == 1) {
                    bc.showresult(Main.this.tv, true);
                }
                else {
                    bc.showresult(Main.this.tv, false);
                }
            }
        });
    }
}
public class uv extends cc {
		...
    protected void onCreate(Bundle savedInstanceState) {
        this.button.setOnClickListener(new View$OnClickListener() {
            public void onClick(View v) {
                String v2 = uv.this.editText.getText().toString().trim();
                if(ua.check(ab.encode3(v2) + ba.encode2(v2) + ca.encode1(v2)) == 1) {
                    bc.showresult(uv.this.tv, true);
                }
                else {
                    bc.showresult(uv.this.tv, false);
                }
            }
        });
    }
}
public class ua {
    static {
        System.loadLibrary("enjoy");
    }
		...
    public static native int check(ua this, String arg1) {
    }
}


2. so处理逻辑


JNI_OnLoad中有两个校验和反调试的地方, 静态分析的时候直接nop掉, 安装完后再替换掉就可以正常调试了

(有检测dex signature和TracerPid什么的)

.text:00001F4C                 BL      check_dex
.text:00001F50                 BL      check_thread


so中的check函数

.text:00001F38                 MOVS    R3, #JNINativeInterface.RegisterNatives
.text:00001F3C                 LDR     R5, [R2,R3]
.text:00001F3E                 LDR     R2, =(off_5E54 - 0x1F48)
.text:00001F40                 MOVS    R0, R4
.text:00001F42                 MOVS    R3, #1
.text:00001F44                 ADD     R2, PC ; off_5E54
.text:00001F46                 BLX     R5

.data:00005E54 off_5E54        JNINativeMethod <byte_5E60, aLjavaLangStrin, check+1>


len(sn)<=120, 原始sn长度范围(x+x+x/3*4 <= 120): 11 ~ 36

从结果来看原始sn长度是36, 但是我后面是从11开始穷举的, 浪费了大量的时间 

.mytext:0000313E                 LDR     R1, [R5]
.mytext:00003140                 MOVS    R3, #JNINativeInterface.GetStringUTFChars
.mytext:00003144                 LDR     R3, [R1,R3]
.mytext:00003146                 MOVS    R2, #0
.mytext:00003148                 MOVS    R1, R7
.mytext:0000314A                 MOVS    R0, R5
.mytext:0000314C                 BLX     R3
.mytext:0000314E                 MOVS    R6, R0
.mytext:00003150                 BL      j_j_strlen_0
.mytext:00003154                 STR     R4, [SP,#0x50+var_4C]
.mytext:00003156                 MOVS    R1, #0          ; c
.mytext:00003158                 CMP     R0, #120
.mytext:0000315A                 BGT     loc_3194
.mytext:0000315C                 ADD     R4, SP, #0x50+s
.mytext:0000315E                 MOVS    R2, #37         ; n
.mytext:00003160                 MOVS    R0, R4          ; s
.mytext:00003162                 BL      j_j_memset_0
.mytext:00003166                 MOVS    R1, R6          ; src
.mytext:00003168                 MOVS    R2, #36         ; n
.mytext:0000316A                 MOVS    R0, R4          ; dest
.mytext:0000316C                 BL      j_j_memcpy_0
.mytext:00003170                 LDR     R2, [R5]
.mytext:00003172                 MOVS    R3, #JNINativeInterface.ReleaseStringUTFChars
.mytext:00003176                 LDR     R3, [R2,R3]
.mytext:00003178                 MOVS    R1, R7
.mytext:0000317A                 MOVS    R2, R6
.mytext:0000317C                 MOVS    R0, R5
.mytext:0000317E                 BLX     R3
.mytext:00003180                 MOVS    R0, R4          ; s
.mytext:00003182                 BL      j_j_strlen_0
.mytext:00003186                 MOVS    R1, R0
.mytext:00003188                 MOVS    R0, R4
.mytext:0000318A                 BL      check_sn


BYTE buf[40];

BYTE key1[8];

BYTE key2[16];

CopyMemory(buf, sn, 36);

FillMemory(buf+36, 0x04, 0x04);

des_enc(buf, sizeof(buf), key1); (这里des_set_key在处理PC2_Table的时候与标准有偏差)

CopyMemory(&key2[12], &buf[32], 4);

rc6_encrypt(buf, 32, key2, sizeof(key2)); (这个不常碰到, 跟了一遍)

memcmp(buf, expected, 32) == 0


rc6与标准的区别: 

Q: 0x9e3779b9L => 0x61C88647L

处理前和处理后都进行了byteswap32


signed int __fastcall check_sn(const void *a1, size_t a2)
{
	...
  if ( a2 == 36 )
  {
    v6 = j_j_malloc(0x28u);
    v7 = v6;
    if ( v6 )
    {
      j_j_memcpy(v6, v3, v4);
      v7[36] = 4;
      v7[37] = 4;
      v7[38] = 4;
      v7[39] = 4;
      do
      {
        v8 = g_key1[v2];
        v9 = 0;
        do
        {
          v17[8 * v2 + v9] = (v8 >> (7 - v9)) & 1;
          ++v9;
        }
        while ( v9 != 8 );
        ++v2;
      }
      while ( v2 != 8 );
      des_set_key((int)v17);
      v10 = 0;
      do
      {
        v11 = &v7[v10];
        j_j_memcpy(&dest, &v7[v10], 8u);
        v15 = 0;
        v16 = 0;
        des_1840((int)&dest, (int)&v15);
        v10 += 8;
        j_j_memcpy(v11, &v15, 8u);
      }
      while ( v10 != 40 );
      update_key2((int)g_key2, (int)&v15);
      rc6_encrypt(v7, 0x20u, (int)g_key2, 16);
      v12 = 0;
      while ( (unsigned __int8)v7[v12] == byte_5D3D[v12] )
      {
        if ( ++v12 == 32 )
        {
          result = 1;
          goto LABEL_14;
        }
      }
    }
  }
  result = 0;
	...
}


3. 穷举


sn以 kxuectf{ 开头,  以 } 结尾

这里直接按sn长度为36位来穷举了

void Des_SetKey(const char Key[8])
{
	static bool K[64];
	static bool KL[56];
	static bool KR[56];
	ByteToBit(K, Key, 64);
	Transform(K, K, PC1_Table, 56);
	CopyMemory(&KL[0], &K[0], 28);
	CopyMemory(&KL[28], &K[0], 28);
	CopyMemory(&KR[0], &K[28], 28);
	CopyMemory(&KR[28], &K[28], 28);
	int offset = 0;
	for(int i=0; i<16; i++) {
		offset += LOOP_Table[i];
		bool Tmp[256];
		for(int n=0; n<48; n++) {
			if (PC2_Table[n] >= 28)
			{
				Tmp[n] = KR[PC2_Table[n]-1-28+offset];
			} else
			{
				Tmp[n] = KL[PC2_Table[n]-1+offset];
			}
		}
		memcpy(SubKey[i], Tmp, 48);
	}
}

void test_sn36()
{
	const char *charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789{}";
	const char *charset2 = "^_`mEJCTNKOGWRSFYVLZQAH[\\]upibejctnkogwrsfyvlzqahmdxKOGWRSFYVLui";
	const char *charset3 = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm76543210?>}{";
	int sn_len = 36;
	int indices[36];
	char sn[40] = "";
	BYTE key1[8] = 
	{
		0xFD, 0xB4, 0x68, 0x54, 0x08, 0xCD, 0x56, 0x4E
	};
	BYTE key2[16] = 
	{
		0x65, 0x48, 0x32, 0xEF, 0xBA, 0xCD, 0x56, 0x4E, 0x0F, 0x9B, 0x1D, 0x27, 0x00, 0x00, 0x00, 0x00
	};
	CopyMemory(sn, "kxuectf{", 8);
	string s1 = encode3((PBYTE)sn, 8);
	for (int k1 = 0; k1 < 64; k1++)
	{
		for (int k2 = 0; k2 < 64; k2++)
		{
			for (int k3 = 0; k3 < 64; k3++)
			{
				BYTE expected[32] = 
				{
					0x42, 0xD3, 0xC3, 0xC2, 0xF1, 0x2A, 0xE9, 0x2D, 0x66, 0xC9, 0x28, 0x22, 0x2C, 0xEB, 0x54, 0x0E, 
					0x94, 0x07, 0xE5, 0x77, 0x4A, 0x92, 0xB7, 0x92, 0x2E, 0x5D, 0xFD, 0xF0, 0xF3, 0x54, 0x9F, 0xC6
				};
				BYTE buf1[8];
				buf1[0] = charset3[k1];
				buf1[1] = charset3[k2];
				buf1[2] = charset3[k3];
				buf1[3] = charset3[63];
				FillMemory(buf1+4, 4, 0x04);
				des_encrypt(buf1, 8, key1);
				CopyMemory(&key2[12], buf1, 4);
				rc6_decrypt(expected, sizeof(expected), key2);
				des_decrypt(expected, sizeof(expected), key1);
				if (memcmp(expected, s1.c_str(), 8) == 0)
				{
					CopyMemory(sn, expected, 32);
					sn[32] = charset3[k1];
					sn[33] = charset3[k2];
					sn[34] = charset3[k3];
					sn[35] = charset3[63];
					sn[sn_len] = 0;
					conver_charset(sn, sn_len, indices, charset, charset3);
					printf("%s\n", sn);
				}
			}
		}
	}
}

>>> kxuectf{D3crypted1sV3rylntere5tin91}



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (2)
雪    币: 53
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Bet 2017-6-25 14:04
2
0
子类的onCreate没有参数
雪    币: 28302
活跃值: (6716)
能力值: ( LV15,RANK:3306 )
在线值:
发帖
回帖
粉丝
风间仁 19 2017-6-25 16:39
3
0
Bet 子类的onCreate没有参数
恩,难怪
游客
登录 | 注册 方可回帖
返回