首页
社区
课程
招聘
[原创]2017ISCC CrackOne:算法分析
发表于: 2023-12-19 23:19 2741

[原创]2017ISCC CrackOne:算法分析

2023-12-19 23:19
2741

一、背景

这个项目值得挑战下,既不会花费太多时间,也可以锻炼下。他是一个base64编码后,带入到so层进行验证的一个过程,当然核心算法还是在so里面,接下来我们详细的分析下。

二、java层代码分析

将APK拖入到jadx中,得到的代码如图所示:
图片描述
首先是将输入的内容经过Digest.encode()进行处理,将处理后的字符串转成字节发送到 checkFlag(byte[] bArr, int i)进行验证。这个过程中encode()看上去像是一个base64编码,这个后面我们在进行验证,为什么要验证呢?有可能是魔改的,一切的猜测尽量用数据显示出来。

三、so层代码分析

把apk解压后,将libISCC.so文件用IDA打开。 在Exports表中我们很容易发现调用的函数。
图片描述
进入到native_checkFlag中,查看他的伪C代码。
图片描述
核心代码逻辑看着还是比较清晰的,对于这段代码我们详细解读下:

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
bool __fastcall native_checkFlag(JNIEnv *env, int a2, int a3, size_t byte_count)
{
  // 分配内存用于存储字节数组的副本
  void *v14 = malloc(byte_count);
  // 从Java字节数组中获取数据并复制到v14中
  ((void (__fastcall *)(JNIEnv *, int, _DWORD, size_t))(*env)->GetByteArrayRegion)(env, a3, 0, byte_count);
 
  // 分配内存用于存储处理后的数据
  void *v7 = malloc(byte_count + 1);
  // 将v7初始化为0
  memset(v7, 0, byte_count + 1);
  // 将v14的内容复制到v7中
  memcpy(v7, v14, byte_count);
 
  int v8 = 0;
  size_t v9 = (size_t)v7 + byte_count;
  for (int i = 0; ; ++i)
  {
    --v8;
    // 循环处理字节数组内容
    if (i >= (int)byte_count / 2)
      break;
    // 交换字节数组内容
    char v11 = *((_BYTE *)v7 + i);
    *((_BYTE *)v7 + i) = *(_BYTE *)(v9 + v8);
    *(_BYTE *)(v9 + v8) = v11 - 5;
  }
 
  // 在处理后的数据的末尾添加0
  *((_BYTE *)v7 + byte_count) = 0;
v7[bc] =0
 
  // 比较处理后的数据和特定字符串
  int v12 = strcmp((const char *)v7, "=0HWYl1SE5UQWFfN?I+PEo.UcshU");
 
  // 释放动态分配的内存
  free(v7);
  free(v14);
 
  // 返回比较结果
  return v12 == 0;
}

四、猜想验证

通过上面的分析,我们知道 只要输入的字符最终的结果等于=0HWYl1SE5UQWFfN?I+PEo.UcshU,就完成项目的验证.
(const char *)v7 = "=0HWYl1SE5UQWFfN?I+PEo.UcshU"
将v7转成字节数组根据上面的算法反向计算出a3的值
a3 是输入的str进行base64编码后得到的所以对a3进行解密就能成功破解
验证是否是base64:

1
2
3
4
5
6
7
let Digest = Java.use("org.isclab.iscc.Digest");
Digest["encode"].implementation = function (srcStr) {
    console.log('encode is called' + ', ' + 'srcStr: ' + srcStr);
    let ret = this.encode(srcStr);
    console.log('encode ret value is ' + ret);
    return ret;
};

随便输入任意值进行hook encode()函数,将结果进行解密没问题确实是base64加密的。

五、算法还原

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
v7_s = '=0HWYl1SE5UQWFfN?I+PEo.UcshU'
byte_array = [ord(char) for char in v7_s]
print("v7_s1 ",byte_array)
print("v7_s2 ",bytes(byte_array))
 
v77 = byte_array
print("v7_s3 ",bytes(v77))
v7 = []
ii = 0
 
print(v7)
v7 = v77
v7 = [90, 109, 120, 104, 90, 51, 116, 74, 85, 48, 78, 68, 83, 107, 70, 87, 81, 85, 53, 69, 83, 49, 108, 89, 87, 72, 48,
      61]
 
v8 = 0
v9 = len(v7)
# [90, 48, 72, 87, 89, 108, 49, 83, 69, 53, 85, 81, 87, 70, 102, 78, 63, 73, 43, 80, 69, 111, 46, 85, 99, 115, 104, 61]
for i in range(len(v7) // 2):
    print(v9 + v8)
    ##正向算法逻辑
    # v8 -= 1
    # v11 = v7[i]
    # v7[i] = v7[v9 + v8]
    # v7[v9 + v8] = v11 - 5
    # print(v9 + v8)
    ## 逆向算法逻辑
    v8 -= 1
    v11 = v7[v9 + v8]
    v7[v9 + v8] = v7[i]
    v7[i] = v11 + 5
    print(v7)
# Set the last element to 0
v7.append(0)
print(v7)
v7 = [90, 109, 120, 104, 90, 51, 116, 74, 85, 48, 78, 68, 83, 107, 70, 87, 81, 85, 53, 69, 83, 49, 108, 89, 87, 72, 48,
      61]
print(bytes(v7).decode()) # ZmxhZ3tJU0NDSkFWQU5ES1lYWH0=

图片描述
将 flag{ISCCJAVANDKYXX} 输入到APP中:
图片描述


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-12-19 23:31 被西贝巴巴编辑 ,原因: 编辑图片
上传的附件:
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-12-20 11:12
1
游客
登录 | 注册 方可回帖
返回
//