eastjni
考點:自定義密碼錶base加密、so
分析
前面的怎麼定位 java 層關鍵位置就略過,查一下錯誤彈窗就能找到。
輸入字符串會作爲 mainactivity/a 的參數輸入:
private boolean a(String paramString)
{
try
{
a locala = new com/a/easyjni/a;
locala.<init>();
bool = ncheck(locala.a(paramString.getBytes()));
return bool;
}
catch (Exception paramString)
{
for (;;)
{
boolean bool = false;
}
}
}
然後又作爲 com/a/easyjni/a 的參數輸入,到達第一層加密:
public class a
{
private static final char[] a = { 105, 53, 106, 76, 87, 55, 83, 48, 71, 88, 54, 117, 102, 49, 99, 118, 51, 110, 121, 52, 113, 56, 101, 115, 50, 81, 43, 98, 100, 107, 89, 103, 75, 79, 73, 84, 47, 116, 65, 120, 85, 114, 70, 108, 86, 80, 122, 104, 109, 111, 119, 57, 66, 72, 67, 77, 68, 112, 69, 97, 74, 82, 90, 78 };
public String a(byte[] paramArrayOfByte)
{
StringBuilder localStringBuilder = new StringBuilder();
for (int i = 0; i <= paramArrayOfByte.length - 1; i += 3)
{
byte[] arrayOfByte = new byte[4];
int j = 0;
int k = 0;
if (j <= 2)
{
if (i + j <= paramArrayOfByte.length - 1) {
arrayOfByte[j] = ((byte)(byte)(k | (paramArrayOfByte[(i + j)] & 0xFF) >>> j * 2 + 2));
}
for (k = (byte)(((paramArrayOfByte[(i + j)] & 0xFF) << (2 - j) * 2 + 2 & 0xFF) >>> 2);; k = 64)
{
j++;
break;
arrayOfByte[j] = ((byte)k);
}
}
arrayOfByte[3] = ((byte)k);
k = 0;
if (k <= 3)
{
if (arrayOfByte[k] <= 63) {
localStringBuilder.append(a[arrayOfByte[k]]);
}
for (;;)
{
k++;
break;
localStringBuilder.append('=');//base
}
}
}
return localStringBuilder.toString();
}
}
每一個字符都進行一次加密,每輪加密都會有 & 、>> 操作,且最後會加上 == ,推斷是 base 加密。然後根據密碼錶 a 判斷是自定義密碼錶的 base 加密方式。
第一次加密完成後的返回值作爲 ncheck 的參數,這是一個加載的 so 中的函數:System.loadLibrary("native");
。分析這個函數需要到 so 文件裏面,so 文件在 lib/armeabi-v7a/libnative.so 。
進入到 ncheck 函數後,再進行兩次加密,分別是:前 16 位與後 16 位互換;前 1 位與後 1 位互換:
signed int __fastcall Java_com_a_easyjni_MainActivity_ncheck(int a1, int a2, int a3)
{
…………
v6 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0);// 字符串傳遞給a1,a1指針取值到v6
if ( strlen(v6) == 32 ) // base加密長度限制32位
{
v7 = 0;
do
{
v8 = &s1[v7]; // s1[0]指針給v8
s1[v7] = v6[v7 + 16]; // s1[0]=v6[16]
v9 = v6[v7++];
v8[16] = v9; // s1[0+16]=v6[0]
}
while ( v7 != 16 ); // 循環16次,每次操作兩個數
// 相當於將前16位於後16位對調
(*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v4 + 680))(v4, v5, v6);
v10 = 0;
do
{
v12 = __OFSUB__(v10, 30);
v11 = v10 - 30 < 0;
v16 = s1[v10];
s1[v10] = s1[v10 + 1]; // s1[0]=s1[1]
s1[v10 + 1] = v16; // s1[1]=s1[0]
v10 += 2;
}
while ( v11 ^ v12 ); // 相當於前一位與後一位對調位置
v13 = memcmp(s1, "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7", 0x20u);//與密文比較
…………
}
思路
首先將密文:MbT3sQgX039i3g==AQOoMQFPskB1Bsc7
還原:
#手動完成前後 16 位互換
c = list("AQOoMQFPskB1Bsc7MbT3sQgX039i3g==")
for i in range(0,len(c),2):
v9 = c[i]
c[i] = c[i+1]
c[i+1] = v9
c = ''.join(c)
print("flag:{}".format(c))
#flag:QAoOQMPFks1BsB7cbM3TQsXg30i9g3==
然後實現自定義密碼錶 base 解碼,我找到的一個腳本:
# coding:utf-8
# 自定義加密表
#s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#原版
s = "i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN"#自定義
def My_base64_encode(inputs):
# 將字符串轉化爲2進制
bin_str = []
for i in inputs:
x = str(bin(ord(i))).replace('0b', '')
bin_str.append('{:0>8}'.format(x))
#print(bin_str)
# 輸出的字符串
outputs = ""
# 不夠三倍數,需補齊的次數
nums = 0
while bin_str:
#每次取三個字符的二進制
temp_list = bin_str[:3]
if(len(temp_list) != 3):
nums = 3 - len(temp_list)
while len(temp_list) < 3:
temp_list += ['0' * 8]
temp_str = "".join(temp_list)
#print(temp_str)
# 將三個8字節的二進制轉換爲4個十進制
temp_str_list = []
for i in range(0,4):
temp_str_list.append(int(temp_str[i*6:(i+1)*6],2))
#print(temp_str_list)
if nums:
temp_str_list = temp_str_list[0:4 - nums]
for i in temp_str_list:
outputs += s[i]
bin_str = bin_str[3:]
outputs += nums * '='
print("Encrypted String:\n%s "%outputs)
def My_base64_decode(inputs):
# 將字符串轉化爲2進制
bin_str = []
for i in inputs:
if i != '=':
x = str(bin(s.index(i))).replace('0b', '')
bin_str.append('{:0>6}'.format(x))
#print(bin_str)
# 輸出的字符串
outputs = ""
nums = inputs.count('=')
while bin_str:
temp_list = bin_str[:4]
temp_str = "".join(temp_list)
#print(temp_str)
# 補足8位字節
if(len(temp_str) % 8 != 0):
temp_str = temp_str[0:-1 * nums * 2]
# 將四個6字節的二進制轉換爲三個字符
for i in range(0,int(len(temp_str) / 8)):
outputs += chr(int(temp_str[i*8:(i+1)*8],2))
bin_str = bin_str[4:]
print("Decrypted String:\n%s "%outputs)
print()
print(" *************************************")
print(" * (1)encode (2)decode *")
print(" *************************************")
print()
num = input("Please select the operation you want to perform:\n")
if(num == "1"):
input_str = input("Please enter a string that needs to be encrypted: \n")
My_base64_encode(input_str)
else:
input_str = input("Please enter a string that needs to be decrypted: \n")
My_base64_decode(input_str)
運行結果:
*************************************
* (1)encode (2)decode *
*************************************
Please select the operation you want to perform:
2
Please enter a string that needs to be decrypted:
QAoOQMPFks1BsB7cbM3TQsXg30i9g3==
Decrypted String:
flag{實踐出真知這不是flag}