【CTF对抗-KCTF2019 变形金刚】此文章归类为:CTF对抗。
本题是我2023年做过加密步骤最繁杂的题目,写一篇wp记录一下
涉及知识点
文件是安卓的apk文件,我们选择jadx进行分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | package com.zhuotong.crackme; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.p003v7.app.AppCompiatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import java.lang.ref.WeakReference; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MainActivity extends AppCompiatActivity { public static final int MSG_LOGIN = 0 ; private static final ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); private static boolean hasLogin; private static Runnable runnable; private Handler handler; private Button login; private String mName; private String mPassword; private EditText name; private EditText password; private static class MyHandler extends Handler { WeakReference<MainActivity> mWeakReference; public MyHandler(MainActivity mainActivity) { this .mWeakReference = new WeakReference<>(mainActivity); } public void handleMessage(Message message) { super .handleMessage(message); MainActivity mainActivity = this .mWeakReference.get(); if (mainActivity != null ) { switch (message.what) { case 0 : String str = (String) message.obj; if (!TextUtils.isEmpty(str)) { StringBuilder sb = new StringBuilder(); for ( int i = 0 ; i < str.length() / 2 ; i++) { sb.append(str.charAt(i)); } str = sb.toString(); } Toast.makeText(mainActivity, "flag{" + str + "}" , 1 ).show(); break ; case 1 : Toast.makeText(mainActivity, "登录失败" , 1 ).show(); break ; } mainActivity.login.setEnabled( true ); } } } /* access modifiers changed from: protected */ @Override // android.support.p000v4.app.SupportActivity, android.support.p003v7.app.AppCompatActivity, android.support.p000v4.app.FragmentActivity public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(C0245R.layout.activity_main); this.login = (Button) findViewById(C0245R.C0247id.login_button); this.handler = new MyHandler(this); this.login.setOnClickListener(new View.OnClickListener() { /* class com.zhuotong.crackme.MainActivity.View$OnClickListenerC02431 */ public void onClick(View view) { MainActivity.this.mName = MainActivity.this.name.getText().toString(); MainActivity.this.mPassword = MainActivity.this.password.getText().toString(); if (TextUtils.isEmpty(MainActivity.this.mName) || TextUtils.isEmpty(MainActivity.this.mPassword)) { Toast.makeText(MainActivity.this, "用户名或密码为空", 1).show(); return; } boolean unused = MainActivity.hasLogin = true; MainActivity.this.login.setEnabled(false); MainActivity.this.login(MainActivity.this.mName, MainActivity.this.mPassword, MainActivity.this.handler); } }); this.name = (EditText) findViewById(C0245R.C0247id.name); this.password = (EditText) findViewById(C0245R.C0247id.password); } /* access modifiers changed from: private */ /* access modifiers changed from: public */ private void login(final String str, final String str2, final Handler handler2) { Toast.makeText(this, "登录中。。。", 1).show(); runnable = new Runnable() { /* class com.zhuotong.crackme.MainActivity.RunnableC02442 */ public void run() { Message obtain = Message.obtain(); StringBuilder sb = new StringBuilder(str2); if (str.equals(sb.reverse().toString())) { obtain.obj = sb.toString(); } else { obtain.what = 1 ; } handler2.sendMessage(obtain); } }; cachedThreadPool.execute(runnable); } } |
程序具有登录功能,接受用户名和密码,并检查反转后的密码是否与用户名相同。如果相同,将返回一个包含flag的Toast消息。
分析完毕,但是没得出什么有用的东西,我们先开文件看一手。
看到已经有账户名了,上面分析发现如果账号反转等于密码的话就会输出flag,我们将账号反转尝试一下。
发现输出“error”,可是我们在代码中并未发现给出error提示的代码,使用字符串搜索也没有该字符串,查看主函数是发现其继承了一个AppCompiatActivity类,仔细一看好家伙,这玩意多了一个i。是个自写类。我们跟进查看看看有没有什么惊喜。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | package android.support.p003v7.app; import android.os.Handler; import android.text.TextUtils; import android.util.Base64; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.zhuotong.crackme.C0245R; import java.io.PrintStream; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /* renamed from: android.support.v7.app.AppCompiatActivity */ public class AppCompiatActivity extends AppCompatActivity { public static final int MSG_LOGIN = 0; private Handler handler; private Button login; private String mName; private String mPassword; private EditText name; private EditText password; /* access modifiers changed from: protected */ /* renamed from: eq */ public native boolean mo4191eq(String str); static { System.loadLibrary("oo000oo"); } /* access modifiers changed from: protected */ @Override // android.support.p003v7.app.AppCompatActivity, android.support.p000v4.app.FragmentActivity public void onStart() { super.onStart(); this.login = (Button) findViewById(C0245R.C0247id.login_button); this.login.setOnClickListener(new View.OnClickListener() { /* class android.support.p003v7.app.AppCompiatActivity.View$OnClickListenerC01791 */ public void onClick(View view) { AppCompiatActivity.this.mName = AppCompiatActivity.this.name.getText().toString(); AppCompiatActivity.this.mPassword = AppCompiatActivity.this.password.getText().toString(); if (TextUtils.isEmpty(AppCompiatActivity.this.mName) || TextUtils.isEmpty(AppCompiatActivity.this.mPassword)) { Toast.makeText(AppCompiatActivity.this, "用户名或密码为空", 1).show(); return; } int i = 0; AppCompiatActivity.this.login.setEnabled(false); if (AppCompiatActivity.this.mo4191eq(AppCompiatActivity.this.mPassword)) { byte[] bytes = AppCompiatActivity.this.mPassword.getBytes(); if (bytes.length != 24) { byte[] bArr = new byte[24]; while (i < bArr.length) { bArr[i] = i < bytes.length ? bytes[i] : (byte) i; i++; } bytes = bArr; } byte[] dec = AppCompiatActivity.dec(bytes, "2ggdrsLgM7iPNYPQrD58Rg==".getBytes()); AppCompiatActivity appCompiatActivity = AppCompiatActivity.this; Toast.makeText(appCompiatActivity, "flag{" + new String(dec) + "}", 1).show(); return; } Toast.makeText(AppCompiatActivity.this, "error", 1).show(); } }); this.name = (EditText) findViewById(C0245R.C0247id.name); this.name.setEnabled(false); this.password = (EditText) findViewById(C0245R.C0247id.password); } /* access modifiers changed from: private */ public static byte [] dec( byte [] bArr, byte [] bArr2) { byte [] decode = Base64.decode(bArr2, 0 ); SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES" ); try { secretKeySpec.getEncoded(); PrintStream printStream = System.out; printStream.println( "getFormat = " + secretKeySpec.getFormat() + " ; getAlgorithm = " + secretKeySpec.getAlgorithm()); Cipher instance = Cipher.getInstance( "AES/CFB/PKCS5Padding" ); PrintStream printStream2 = System.out; printStream2.println( "getBlockSize = " + instance.getBlockSize()); instance.init( 2 , secretKeySpec, new IvParameterSpec( new byte [instance.getBlockSize()])); return instance.doFinal(decode); } catch (Throwable th) { th.printStackTrace(); return null ; } } } |
代码包含了一些操作 EditText、Button 和 Toast 的逻辑,实现了一个简单的登录功能。
在 onStart() 方法中,有 login、name、password 这三个控件,并添加了一个点击监听器。当登录按钮被点击时,代码会尝试使用 mo4191eq() 方法判断密码是否正确,如果正确,则使用 dec() 方法对密码进行解密,并通过 Toast 显示 flag。
总的来说,这段代码是一个简单的登录功能,使用了一些常见的 Android 应用程序组件和加密算法。
主要发现这里使用了一个native方法,将apk文件使用压缩包打开,提取出该so文件,使用ida观察.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | jint JNI_OnLoad(JavaVM *vm, void *reserved) { int v3; // r5 int v4; // r6 int v5; // [sp+0h] [bp-18h] BYREF v5 = 0; if ( (*vm)->GetEnv(vm, ( void **)&v5, 65540) ) return -1; v3 = v5; v4 = (*( int (__fastcall **)( int , void *))(*(_DWORD *)v5 + 24))(v5, off_4010); dword_4110 = (*( int (__fastcall **)( int , int ))(*(_DWORD *)v3 + 84))(v3, v4); if ( !v4 || (*( int (__fastcall **)( int , int , char **, int ))(*(_DWORD *)v3 + 860))(v3, v4, off_4014, 1) <= -1 ) return -1; else return 65542; } |
这里主要是动态注册Native 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | char *datadiv_decode5009363700628197108() { int i; // r0 int j; // r0 int k; // r0 char *result; // r0 for ( i = 0; i != 37; ++i ) byte_4020[i] ^= 0xA5u; for ( j = 0; j != 66; ++j ) byte_4050[j] ^= 0xA5u; for ( k = 0; k != 42; ++k ) byte_40A0[k] ^= 0x84u; result = &byte_40D0; byte_40CA ^= 0xFCu; byte_40CB ^= 0xFCu; byte_40CC ^= 0xFCu; byte_40D0 ^= 0x62u; byte_40D1 ^= 0x62u; byte_40D2 ^= 0x62u; byte_40D3 ^= 0x62u; byte_40D4 ^= 0x62u; byte_40D5 ^= 0x62u; word_40D6 ^= 0x6262u; byte_40D8 ^= 0x62u; byte_40D9 ^= 0x62u; byte_40DA ^= 0x62u; byte_40DB ^= 0x62u; byte_40DC ^= 0x62u; byte_40DD ^= 0x62u; byte_40DE ^= 0x62u; byte_40DF ^= 0x62u; byte_40E0 ^= 0x62u; byte_40E1 ^= 0x62u; byte_40E2 ^= 0x62u; byte_40E3 ^= 0x62u; byte_40E4 ^= 0x62u; byte_40E5 ^= 0x62u; return result; } |
这一段代码对一大串字符做了处理,我们使用脚本分析,看看处理出了什么东西。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<map> #include<vector> #include<queue> #include<stack> #include<set> #include<string> #include<cstring> #include<list> #include<stdlib.h> #include<windows.h> using namespace std; typedef int status; typedef int selemtype; int v3; // r10 char *v4; // r6 char *v5; // r8 char *v6; // r11 int v7; // r0 int v8; // r2 char *v9; // r1 int v10; // r3 int v11; // r1 unsigned int v12; // r2 int v13; // r3 int v14; // r0 int v15; // r4 char v16; // r0 char *v17; // r3 char *v18; // r5 // r5 int v20; // r1 int v21; // r0 // r1 int v23; // r2 int v24; // r8 unsigned int v25; // r5 char *v26; // r0 int v27; // r10 unsigned int v28; // r2 int v29; // r12 bool v30; // zf char *v31; // r4 int v32; // r3 bool v33; // zf int v34; // r3 int v35; // r1 char v36; // r11 char v37; // lr int v38; // r3 unsigned __int8 v39; // r1 char *v40; // r2 int v41; // r3 int v42; // t1 char v44; // r1 unsigned int v45; // [sp+4h] [bp-234h] unsigned int v46; // [sp+8h] [bp-230h] unsigned int v47; // [sp+10h] [bp-228h] char *v48; // [sp+14h] [bp-224h] char v49[257]; // [sp+18h] [bp-220h] BYREF char v50[257]; // [sp+118h] [bp-120h] /* _ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\||| : |||// \ / _||||| -:- |||||- \ | | \\\ - /// | | | \_| ''\---/'' | | \ .-\__ `-` ___/-. / ___`. .' /--.--\ `. . __ ."" '< `.___\_<|>_/___.' >'"". | | : `- \`.;`\ _ /`;.`/ - ` : | | \ \ `-. \_ __\ /__ _/ .-` / / ======`-.____`-.___\_____/___.-`____.-'====== `=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 佛祖保佑 永不宕机 永无BUG */ unsigned char ida_chars1[] = { 0x93, 0x90, 0x95, 0xC3, 0x9C, 0x95, 0x9C, 0xC6, 0x88, 0x92, 0x97, 0x94, 0x92, 0x88, 0x96, 0x93, 0x91, 0x92, 0x88, 0x9C, 0x96, 0x96, 0x94, 0x88, 0xC6, 0x9D, 0x97, 0xC1, 0xC3, 0x9D, 0xC7, 0x9C, 0x9D, 0xC0, 0x9C, 0x9D, 0xA5 }; unsigned char ida_chars2[] = { 0x84, 0x9F, 0x86, 0x81, 0x80, 0x83, 0x8D, 0x8C, 0x8E, 0x88, 0x8F, 0x8A, 0xC5, 0xDB, 0xFA, 0xFE, 0xF8, 0xDE, 0xD8, 0x9A, 0x99, 0x9B, 0x89, 0x8B, 0xE5, 0xFB, 0xC4, 0xC7, 0xC6, 0xC1, 0xC0, 0xC3, 0xC2, 0xCD, 0xCC, 0xCF, 0xCE, 0xC9, 0xC8, 0xCB, 0xCA, 0xD5, 0xD4, 0xD7, 0xD6, 0xD1, 0xD0, 0xD3, 0xD2, 0xDD, 0xDC, 0xDF, 0x95, 0x94, 0x97, 0x96, 0x91, 0x90, 0x93, 0x92, 0x9D, 0x9C, 0xF9, 0x82, 0x9E, 0xA5 }; unsigned char ida_chars3[] = { 0xE5, 0xEA, 0xE0, 0xF6, 0xEB, 0xED, 0xE0, 0xAB, 0xF7, 0xF1, 0xF4, 0xF4, 0xEB, 0xF6, 0xF0, 0xAB, 0xF2, 0xB3, 0xAB, 0xE5, 0xF4, 0xF4, 0xAB, 0xC5, 0xF4, 0xF4, 0xC7, 0xEB, 0xE9, 0xF4, 0xED, 0xE5, 0xF0, 0xC5, 0xE7, 0xF0, 0xED, 0xF2, 0xED, 0xF0, 0xFD, 0x84 }; unsigned char ida_chars4[] = { 0x99, 0x8D, 0xFC, 0x00, 0x00, 0x00, 0x4A, 0x2E, 0x08, 0x03, 0x14, 0x03, 0x4D, 0x0E, 0x03, 0x0C, 0x05, 0x4D, 0x31, 0x16, 0x10, 0x0B, 0x0C, 0x05, 0x59, 0x4B, 0x38, 0x62 }; unsigned char ida_chars[] = { 0xD7, 0xDF, 0x02, 0xD4, 0xFE, 0x6F, 0x53, 0x3C, 0x25, 0x6C, 0x99, 0x97, 0x06, 0x56, 0x8F, 0xDE, 0x40, 0x11, 0x64, 0x07, 0x36, 0x15, 0x70, 0xCA, 0x18, 0x17, 0x7D, 0x6A, 0xDB, 0x13, 0x30, 0x37, 0x29, 0x60, 0xE1, 0x23, 0x28, 0x8A, 0x50, 0x8C, 0xAC, 0x2F, 0x88, 0x20, 0x27, 0x0F, 0x7C, 0x52, 0xA2, 0xAB, 0xFC, 0xA1, 0xCC, 0x21, 0x14, 0x1F, 0xC2, 0xB2, 0x8B, 0x2C, 0xB0, 0x3A, 0x66, 0x46, 0x3D, 0xBB, 0x42, 0xA5, 0x0C, 0x75, 0x22, 0xD8, 0xC3, 0x76, 0x1E, 0x83, 0x74, 0xF0, 0xF6, 0x1C, 0x26, 0xD1, 0x4F, 0x0B, 0xFF, 0x4C, 0x4D, 0xC1, 0x87, 0x03, 0x5A, 0xEE, 0xA4, 0x5D, 0x9E, 0xF4, 0xC8, 0x0D, 0x62, 0x63, 0x3E, 0x44, 0x7B, 0xA3, 0x68, 0x32, 0x1B, 0xAA, 0x2D, 0x05, 0xF3, 0xF7, 0x16, 0x61, 0x94, 0xE0, 0xD0, 0xD3, 0x98, 0x69, 0x78, 0xE9, 0x0A, 0x65, 0x91, 0x8E, 0x35, 0x85, 0x7A, 0x51, 0x86, 0x10, 0x3F, 0x7F, 0x82, 0xDD, 0xB5, 0x1A, 0x95, 0xE7, 0x43, 0xFD, 0x9B, 0x24, 0x45, 0xEF, 0x92, 0x5C, 0xE4, 0x96, 0xA9, 0x9C, 0x55, 0x89, 0x9A, 0xEA, 0xF9, 0x90, 0x5F, 0xB8, 0x04, 0x84, 0xCF, 0x67, 0x93, 0x00, 0xA6, 0x39, 0xA8, 0x4E, 0x59, 0x31, 0x6B, 0xAD, 0x5E, 0x5B, 0x77, 0xB1, 0x54, 0xDC, 0x38, 0x41, 0xB6, 0x47, 0x9F, 0x73, 0xBA, 0xF8, 0xAE, 0xC4, 0xBE, 0x34, 0x01, 0x4B, 0x2A, 0x8D, 0xBD, 0xC5, 0xC6, 0xE8, 0xAF, 0xC9, 0xF5, 0xCB, 0xFB, 0xCD, 0x79, 0xCE, 0x12, 0x71, 0xD2, 0xFA, 0x09, 0xD5, 0xBC, 0x58, 0x19, 0x80, 0xDA, 0x49, 0x1D, 0xE6, 0x2E, 0xE3, 0x7E, 0xB7, 0x3B, 0xB3, 0xA0, 0xB9, 0xE5, 0x57, 0x6E, 0xD9, 0x08, 0xEB, 0xC7, 0xED, 0x81, 0xF1, 0xF2, 0xBF, 0xC0, 0xA7, 0x4A, 0xD6, 0x2B, 0xB4, 0x72, 0x9D, 0x0E, 0x6D, 0xEC, 0x48, 0xE2, 0x33 }; char vs16[] = "2409715836dbeafc" ; int main () { for ( int i = 0 ; i < 38 ; i ++ ) { ida_chars1[i]^=0xa5; } for ( int i = 0 ; i < 66 ; i ++ ) { ida_chars2[i]^=0xa5; } for ( int i = 0 ; i <42 ; i ++ ) { ida_chars3[i]^=0x84; } for ( int i = 0 ; i <28 ; i++ ) { if (i<=2) { ida_chars4[i]^=0xfc; } else { ida_chars4[i]^=0x62; } } ida_chars4[2]= '"' ; printf ( "%s\n%s\n%s\n%s\n" ,ida_chars1,ida_chars2,ida_chars3,ida_chars4); |
输出结果:
1 2 3 4 | 650f909c-7217-3647-9331-c82df8b98e98 !:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\'; android/support/v7/app/AppCompiatActivity eq"bbb(Ljava/lang/String;)Z |
发现第一个字符串像是一串序列号,第二个字符串是一个变化的base64密码表,第三第四个则是调用我们的eq函数
JNI_Onload() 里边有两个off_4010 off_4014 分别对应的就是第三第四个字符串。
我们对密码表进行跟进
发现784函数调用了该密码表,肯定是在其中进行了base64变表加密。
查看整个784函数,我们将该函数分为几段来进行讲解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | if ( v3 ) { v7 = 0; v8 = v3; v9 = byte_4020; do { v10 = (unsigned __int8 )*v9++; if ( v10 != 45 ) *((_BYTE *)v5 + v7++) = v10; --v8; } while ( v8 ); if ( v7 >= 1 ) { v11 = v7 - 1; v12 = -8; v13 = 0; v14 = 0; do { if ( (v13 | (v12 >> 2)) > 3 ) { v15 = v14; } else { v15 = v14 + 1; v4[v14] = 45; } v16 = *((_BYTE *)v5 + v11--); v13 += 0x40000000; v4[v15] = v16; ++v12; v14 = v15 + 1; } while ( v11 != -1 ); if ( v15 >= 0 ) { v17 = v6; while ( 1 ) { v18 = (_BYTE *)*v4; if ( (unsigned __int8 )((_BYTE)v18 - 97) <= 5u ) break ; if ( (unsigned __int8 )((_BYTE)v18 - 48) <= 9u ) { v18 = ( char *)&unk_23DE + (_DWORD)v18 - 48; goto LABEL_18; } LABEL_19: *v17++ = (unsigned __int8 )v18; --v14; ++v4; if ( !v14 ) goto LABEL_20; } v18 = ( char *)&unk_23D8 + (_DWORD)v18 - 97; LABEL_18: LOBYTE(v18) = *v18; goto LABEL_19; } } } |
这一串呢,首先是取出我们之前异或得到的那个类似于序列号的字符串,在此处实际上是作为rc4的key,然后对对其处理方式是删除其中所有的'-'然后逆序,再加上'-',再利用码表,将其替换成码表里面的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | for ( i = 0; i != 256; ++i ) { sub_D20(i, v3); v50[i] = v6[v20]; } v21 = (unsigned __int8 )(v50[0] - 41); v49[0] = v49[v21]; v49[v21] = -41; for ( j = 1; j != 256; ++j ) { v23 = (unsigned __int8 )v49[j]; v21 = (v21 + (unsigned __int8 )v50[j] + v23) % 256; v49[j] = v49[v21]; v49[v21] = v23; } v24 = strlen (v48); v25 = v6[3]; v46 = 8 * (3 - -3 * (v24 / 3)); v45 = v25 + v46 / 6; v26 = malloc (v45 + 1); if ( !v24 ) goto LABEL_44; v27 = 0; v28 = 0; v29 = 0; v47 = v25; |
这一段就是对rc4的s盒子,t盒进行处理,然而本次的rc4为魔改rc4它使用了自己给出的S盒。内容储存在unk_23E8中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | while ( 1 ) { v27 = (v27 + 1) % 256; v35 = (unsigned __int8 )v49[v27]; v29 = (v29 + v35) % 256; v49[v27] = v49[v29]; v49[v29] = v35; v36 = v49[(unsigned __int8 )(v35 + v49[v27])] ^ v48[v28]; if ( !v28 ) break ; v37 = 3 * (v28 / 3); if ( v37 == v28 ) break ; v30 = v28 == 1; if ( v28 != 1 ) v30 = v37 + 1 == v28; if ( v30 ) { v26[v47 + v28] = byte_4050[(unsigned __int8 )v26[v47 + v28] | (v36 >> 4)]; v31 = &v26[v47 + v28]; v32 = (4 * v36) & 0x3C; v31[1] = v32; if ( v28 + 1 >= v24 ) { v44 = byte_4050[v32]; v31[2] = 52; goto LABEL_43; } } else { v33 = v28 == 2; if ( v28 != 2 ) v33 = v37 + 2 == v28; if ( v33 ) { v34 = v47 + v28; ++v47; v26[v34] = byte_4050[(unsigned __int8 )v26[v34] | ((unsigned __int8 )(v36 & 0xC0) >> 6)] ^ 0xF; v26[v34 + 1] = byte_4050[v36 & 0x3F]; } } LABEL_40: if ( ++v28 >= v24 ) goto LABEL_44; } |
这一段就是将每个字符先rc4加密在使用base64加密,同时进行。
但是每当迭代器为2的倍数时需要异或一个0xF。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | v26[v47 + v28] = byte_4050[v36 >> 2] ^ 7; v31 = &v26[v47 + v28]; v38 = (16 * v36) & 0x30; v31[1] = v38; if ( v28 + 1 < v24 ) goto LABEL_40; v44 = byte_4050[v38]; *((_WORD *)v31 + 1) = 15163; LABEL_43: v31[1] = v44; LABEL_44: if ( v46 ) { v39 = 1; v40 = &byte_24E8; do { v41 = (unsigned __int8 )v26[v25++]; v42 = (unsigned __int8 )*v40++; if ( v42 != v41 ) v39 = 0; } while ( v25 < v45 ); } else { return 1; } return v39; |
这一段是每当迭代器为4的倍数时就需要将密文异或一个0x7,然后与储存的值进行比较。至此解析完毕,那么这个密文肯定就是密码。
我们需要将密文先按规则异或回去然后base64 解码。
脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import string s = " {9*8ga*l!Tn?@#fj'j$\g;;" cc = '' for i in xrange ( len (s)): if (i % 4 = = 0 ): cc + = chr ( ord (s[i]) ^ 7 ) elif (i % 4 = = 2 ): cc + = chr ( ord (s[i]) ^ 0xF ) else : cc + = s[i] my_base64table = "!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\\';" std_base64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" t = string.maketrans(my_base64table, std_base64table) print map ( ord , cc.translate(t).decode( 'base64' )) #[253, 30, 138, 78, 9, 202, 144, 3, 231, 241, 133, 159, 155, 247, 131, 62, 14] |
然后我们可以得到处理后的密钥的值。
接下来我们需要处理rc4的key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | v3 = 36; v5 = ( char *) malloc (v3); v6 = ( char *) malloc (v3); v4 = ( char *) malloc (v3); if (v3) { v7 = 0; v8 = v3; v9 = ida_chars5; do { v10 = *v9++; if (v10!=45) { *(v5 + v7++) = v10; } --v8; } while (v8); if ( v7 >= 1 ) { v11 = v7 - 1; v12 = -8; v13 = 0; v14 = 0; do { if ( (v13 | (v12 >> 2)) > 3 ) { v15 = v14; } else { v15 = v14 + 1; v4[v14] = '-' ; } v16 = *(v5 + v11--); v13 += 0x40000000; v4[v15] = v16; ++v12; v14 = v15 + 1; } while ( v11 != -1 ); } for ( int i = 0 ; i < 36 ; i ++ ) { if ((unsigned char )(v4[i]- 'a' ) <= 5u ) { v4[i] = vs16[v4[i]- 'a' +10]; } else if ((unsigned char )(v4[i]- '0' ) <= 9u ) { v4[i]= vs16[v4[i]- '0' ]; } } printf ( "%s\n" ,v4); } |
得到36f36b3c-a03e-4996-8759-8408e626c215
然后初始化RC4的密钥流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | char s[257]={0}; unsigned char K[257]={0}; memcpy (&s[0],&ida_chars[0],0x100); for ( int i = 0 ; i < 256 ; i ++ ) { K[i]=v4[i%36]; //printf("%d,",K[i]); } int j = 0; j = (unsigned char )(K[0] - 41); s[0]=s[j]; s[j]=0xd7; for ( int i = 1 ; i<256 ; i ++ ) { int tmp = (unsigned char )s[i]; j =(j+(unsigned char )K[i]+tmp)%256; s[i]=s[j]; s[j]=tmp; } for ( int i=0;i<0x100;i++){ printf ( "%02X " ,(unsigned char )s[i]); if ((i+1)%16==0){ printf ( "\n" ); } } |
异或得到答案
1 2 3 4 5 6 7 8 9 10 11 12 | int txi = 0 , txj = 0; unsigned char tx =0; for ( int i = 0 ; i < 16 ; i ++ ) { txi = (txi+1)%256; tx = (unsigned char )s[txi]; txj=(txj+tx)%256; s[txi]=s[txj]; s[txj]=tx; // printf("%X,",s[tx+s[txi]]); printf ( "%c" ,s[(tx+s[txi])%256]^debase[i]); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<map> #include<vector> #include<queue> #include<stack> #include<set> #include<string> #include<cstring> #include<list> #include<stdlib.h> #include<windows.h> using namespace std; typedef int status; typedef int selemtype; int v3; // r10 char *v4; // r6 char *v5; // r8 char *v6; // r11 int v7; // r0 int v8; // r2 char *v9; // r1 int v10; // r3 int v11; // r1 unsigned int v12; // r2 int v13; // r3 int v14; // r0 int v15; // r4 char v16; // r0 char *v17; // r3 char *v18; // r5 // r5 int v20; // r1 int v21; // r0 // r1 int v23; // r2 int v24; // r8 unsigned int v25; // r5 char *v26; // r0 int v27; // r10 unsigned int v28; // r2 int v29; // r12 bool v30; // zf char *v31; // r4 int v32; // r3 bool v33; // zf int v34; // r3 int v35; // r1 char v36; // r11 char v37; // lr int v38; // r3 unsigned __int8 v39; // r1 char *v40; // r2 int v41; // r3 int v42; // t1 char v44; // r1 unsigned int v45; // [sp+4h] [bp-234h] unsigned int v46; // [sp+8h] [bp-230h] unsigned int v47; // [sp+10h] [bp-228h] char *v48; // [sp+14h] [bp-224h] char v49[257]; // [sp+18h] [bp-220h] BYREF char v50[257]; // [sp+118h] [bp-120h] /* _ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\||| : |||// \ / _||||| -:- |||||- \ | | \\\ - /// | | | \_| ''\---/'' | | \ .-\__ `-` ___/-. / ___`. .' /--.--\ `. . __ ."" '< `.___\_<|>_/___.' >'"". | | : `- \`.;`\ _ /`;.`/ - ` : | | \ \ `-. \_ __\ /__ _/ .-` / / ======`-.____`-.___\_____/___.-`____.-'====== `=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 佛祖保佑 永不宕机 永无BUG */ unsigned char ida_chars1[] = { 0x93, 0x90, 0x95, 0xC3, 0x9C, 0x95, 0x9C, 0xC6, 0x88, 0x92, 0x97, 0x94, 0x92, 0x88, 0x96, 0x93, 0x91, 0x92, 0x88, 0x9C, 0x96, 0x96, 0x94, 0x88, 0xC6, 0x9D, 0x97, 0xC1, 0xC3, 0x9D, 0xC7, 0x9C, 0x9D, 0xC0, 0x9C, 0x9D, 0xA5 }; unsigned char ida_chars2[] = { 0x84, 0x9F, 0x86, 0x81, 0x80, 0x83, 0x8D, 0x8C, 0x8E, 0x88, 0x8F, 0x8A, 0xC5, 0xDB, 0xFA, 0xFE, 0xF8, 0xDE, 0xD8, 0x9A, 0x99, 0x9B, 0x89, 0x8B, 0xE5, 0xFB, 0xC4, 0xC7, 0xC6, 0xC1, 0xC0, 0xC3, 0xC2, 0xCD, 0xCC, 0xCF, 0xCE, 0xC9, 0xC8, 0xCB, 0xCA, 0xD5, 0xD4, 0xD7, 0xD6, 0xD1, 0xD0, 0xD3, 0xD2, 0xDD, 0xDC, 0xDF, 0x95, 0x94, 0x97, 0x96, 0x91, 0x90, 0x93, 0x92, 0x9D, 0x9C, 0xF9, 0x82, 0x9E, 0xA5 }; unsigned char ida_chars3[] = { 0xE5, 0xEA, 0xE0, 0xF6, 0xEB, 0xED, 0xE0, 0xAB, 0xF7, 0xF1, 0xF4, 0xF4, 0xEB, 0xF6, 0xF0, 0xAB, 0xF2, 0xB3, 0xAB, 0xE5, 0xF4, 0xF4, 0xAB, 0xC5, 0xF4, 0xF4, 0xC7, 0xEB, 0xE9, 0xF4, 0xED, 0xE5, 0xF0, 0xC5, 0xE7, 0xF0, 0xED, 0xF2, 0xED, 0xF0, 0xFD, 0x84 }; unsigned char ida_chars4[] = { 0x99, 0x8D, 0xFC, 0x00, 0x00, 0x00, 0x4A, 0x2E, 0x08, 0x03, 0x14, 0x03, 0x4D, 0x0E, 0x03, 0x0C, 0x05, 0x4D, 0x31, 0x16, 0x10, 0x0B, 0x0C, 0x05, 0x59, 0x4B, 0x38, 0x62 }; unsigned char ida_chars[] = { 0xD7, 0xDF, 0x02, 0xD4, 0xFE, 0x6F, 0x53, 0x3C, 0x25, 0x6C, 0x99, 0x97, 0x06, 0x56, 0x8F, 0xDE, 0x40, 0x11, 0x64, 0x07, 0x36, 0x15, 0x70, 0xCA, 0x18, 0x17, 0x7D, 0x6A, 0xDB, 0x13, 0x30, 0x37, 0x29, 0x60, 0xE1, 0x23, 0x28, 0x8A, 0x50, 0x8C, 0xAC, 0x2F, 0x88, 0x20, 0x27, 0x0F, 0x7C, 0x52, 0xA2, 0xAB, 0xFC, 0xA1, 0xCC, 0x21, 0x14, 0x1F, 0xC2, 0xB2, 0x8B, 0x2C, 0xB0, 0x3A, 0x66, 0x46, 0x3D, 0xBB, 0x42, 0xA5, 0x0C, 0x75, 0x22, 0xD8, 0xC3, 0x76, 0x1E, 0x83, 0x74, 0xF0, 0xF6, 0x1C, 0x26, 0xD1, 0x4F, 0x0B, 0xFF, 0x4C, 0x4D, 0xC1, 0x87, 0x03, 0x5A, 0xEE, 0xA4, 0x5D, 0x9E, 0xF4, 0xC8, 0x0D, 0x62, 0x63, 0x3E, 0x44, 0x7B, 0xA3, 0x68, 0x32, 0x1B, 0xAA, 0x2D, 0x05, 0xF3, 0xF7, 0x16, 0x61, 0x94, 0xE0, 0xD0, 0xD3, 0x98, 0x69, 0x78, 0xE9, 0x0A, 0x65, 0x91, 0x8E, 0x35, 0x85, 0x7A, 0x51, 0x86, 0x10, 0x3F, 0x7F, 0x82, 0xDD, 0xB5, 0x1A, 0x95, 0xE7, 0x43, 0xFD, 0x9B, 0x24, 0x45, 0xEF, 0x92, 0x5C, 0xE4, 0x96, 0xA9, 0x9C, 0x55, 0x89, 0x9A, 0xEA, 0xF9, 0x90, 0x5F, 0xB8, 0x04, 0x84, 0xCF, 0x67, 0x93, 0x00, 0xA6, 0x39, 0xA8, 0x4E, 0x59, 0x31, 0x6B, 0xAD, 0x5E, 0x5B, 0x77, 0xB1, 0x54, 0xDC, 0x38, 0x41, 0xB6, 0x47, 0x9F, 0x73, 0xBA, 0xF8, 0xAE, 0xC4, 0xBE, 0x34, 0x01, 0x4B, 0x2A, 0x8D, 0xBD, 0xC5, 0xC6, 0xE8, 0xAF, 0xC9, 0xF5, 0xCB, 0xFB, 0xCD, 0x79, 0xCE, 0x12, 0x71, 0xD2, 0xFA, 0x09, 0xD5, 0xBC, 0x58, 0x19, 0x80, 0xDA, 0x49, 0x1D, 0xE6, 0x2E, 0xE3, 0x7E, 0xB7, 0x3B, 0xB3, 0xA0, 0xB9, 0xE5, 0x57, 0x6E, 0xD9, 0x08, 0xEB, 0xC7, 0xED, 0x81, 0xF1, 0xF2, 0xBF, 0xC0, 0xA7, 0x4A, 0xD6, 0x2B, 0xB4, 0x72, 0x9D, 0x0E, 0x6D, 0xEC, 0x48, 0xE2, 0x33 }; char vs16[] = "2409715836dbeafc" ; int main () { for ( int i = 0 ; i < 38 ; i ++ ) { ida_chars1[i]^=0xa5; } for ( int i = 0 ; i < 66 ; i ++ ) { ida_chars2[i]^=0xa5; } for ( int i = 0 ; i <42 ; i ++ ) { ida_chars3[i]^=0x84; } for ( int i = 0 ; i <28 ; i++ ) { if (i<=2) { ida_chars4[i]^=0xfc; } else { ida_chars4[i]^=0x62; } } ida_chars4[2]= '"' ; printf ( "%s\n%s\n%s\n%s\n" ,ida_chars1,ida_chars2,ida_chars3,ida_chars4); // {9*8ga*l!Tn?@#fj'j$\\g;; //650f909c-7217-3647-9331-c82df8b98e98 char ida_chars5[37]={0}; unsigned char debase[26]={0xFD, 0x1E, 0x8A, 0x4E, 0x09, 0xCA, 0x90, 0x03, 0xE7, 0xF1, 0x85, 0x9F, 0x9B, 0xF7, 0x83, 0x3E}; for ( int i = 0 ; i < 36 ; i ++ ) { ida_chars5[i]=ida_chars1[i]; } printf ( "%s\n" ,ida_chars5); int k = 0; v3 = 36; v5 = ( char *) malloc (v3); v6 = ( char *) malloc (v3); v4 = ( char *) malloc (v3); if (v3) { v7 = 0; v8 = v3; v9 = ida_chars5; do { v10 = *v9++; if (v10!=45) { *(v5 + v7++) = v10; } --v8; } while (v8); if ( v7 >= 1 ) { v11 = v7 - 1; v12 = -8; v13 = 0; v14 = 0; do { if ( (v13 | (v12 >> 2)) > 3 ) { v15 = v14; } else { v15 = v14 + 1; v4[v14] = '-' ; } v16 = *(v5 + v11--); v13 += 0x40000000; v4[v15] = v16; ++v12; v14 = v15 + 1; } while ( v11 != -1 ); } for ( int i = 0 ; i < 36 ; i ++ ) { if ((unsigned char )(v4[i]- 'a' ) <= 5u ) { v4[i] = vs16[v4[i]- 'a' +10]; } else if ((unsigned char )(v4[i]- '0' ) <= 9u ) { v4[i]= vs16[v4[i]- '0' ]; } } printf ( "%s\n" ,v4); } char s[257]={0}; unsigned char K[257]={0}; //v4="09f09b0c-ae0e-baa9-4f2a-4be4e9d9cdc2"; memcpy (&s[0],&ida_chars[0],0x100); for ( int i = 0 ; i < 256 ; i ++ ) { K[i]=v4[i%36]; //printf("%d,",K[i]); } int j = 0; j = (unsigned char )(K[0] - 41); s[0]=s[j]; s[j]=0xd7; for ( int i = 1 ; i<256 ; i ++ ) { int tmp = (unsigned char )s[i]; j =(j+(unsigned char )K[i]+tmp)%256; s[i]=s[j]; s[j]=tmp; } for ( int i=0;i<0x100;i++){ printf ( "%02X " ,(unsigned char )s[i]); if ((i+1)%16==0){ printf ( "\n" ); } } int txi = 0 , txj = 0; unsigned char tx =0; for ( int i = 0 ; i < 16 ; i ++ ) { txi = (txi+1)%256; tx = (unsigned char )s[txi]; txj=(txj+tx)%256; s[txi]=s[txj]; s[txj]=tx; // printf("%X,",s[tx+s[txi]]); printf ( "%c" ,s[(tx+s[txi])%256]^debase[i]); } } |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 650f909c-7217-3647-9331-c82df8b98e98 !:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\'; android/support/v7/app/AppCompiatActivity eq"bbb(Ljava/lang/String;)Z 650f909c-7217-3647-9331-c82df8b98e98 36f36b3c-a03e-4996-8759-8408e626c215 F0 37 E1 9B 2A 15 17 9F D7 58 4D 6E 33 A0 39 AE 04 D0 BE ED F8 66 5E 00 D6 91 2F C3 10 4C F7 A6 C1 EC 6D 0B 50 65 BB 34 FA A4 2D 3B 23 A1 96 D5 1D 38 56 0A 5D 4F E4 CC 24 0D 12 87 35 85 8E 6F C6 13 9A D3 FC E7 08 AC B7 E9 B0 E8 41 AA 55 53 C2 42 BC E6 0F 8A 86 A8 CF 84 C5 48 74 36 07 EB 88 51 F6 7F 57 05 63 3E FE B8 C9 F5 AF DF EA 82 44 F9 CD 06 BA 30 47 40 DE FD 1C 7C 11 5C 02 31 2C 9C 5F 46 27 C4 83 73 16 90 20 76 7B F2 E3 F3 77 52 80 25 09 26 3F C7 18 1B A3 FF FB CB A9 8C 54 7A 68 B4 70 4B E2 49 22 7E A5 B6 81 9D 4E 67 F1 A7 3C D9 94 EF 32 6B 1F B1 60 B9 64 59 01 B3 7D E0 6C AD 97 19 B5 3A F4 D8 8D 98 03 93 1A DC 1E 4A C0 5A E5 D1 3D 14 C8 79 BD 43 DB 69 D2 61 95 9E 21 45 89 2B AB 29 A2 8B 2E D4 0E 62 CA 28 DA 5B 72 8F 99 75 EE 78 0C 71 BF DD CE 92 6A B2 fu0kzHp2aqtZAuY6 |
然后我们将fu0kzHp2aqtZAuY6输入到软件中就可以拿到flag了
收益良多
更多【CTF对抗-KCTF2019 变形金刚】相关视频教程:www.yxfzedu.com