1
0
0

MiniVNCTF

2025-12-07

考察了基础的安卓逆向流程以及普通的xtea魔改,难度为简单

ezAndroid

jadx打开程序,定位到Mainactivity直接来看程序流程
image
程序判断了输入flag的长度和格式,然后分割为两部分,交由FlagChecker类中的check函数校验

check1

image
check1使用AES/ECB/NoPadding加密
key来自 context.getString(R.string.secret);
image
key:wowYouFindme!!!!
密文:1gtKGI6VxcyrHHJuif5K2A==
由于是直接调用标准库函数,所以标准算法直接解密即可
image
flag1:u_Know_@ndro1d_A

check2

image
check2是native函数,在so中实现,找到对应函数
image
逻辑很清晰,输入经过sub_250F0处理后跟密文比较
image
sub_250F0是一个被魔改过后的xtea,魔改了位移数,sum变化位置,还有delta
delta由全局变量存储,查找引用发现还有一个函数使用了delta
image
image

这个函数偷偷修改了delta的值
那为什么这个函数会被执行呢?
image
这个函数位于init_array段
so逆向筑基-hook init init_array 和JNI_OnLoad - 简书
在linker加载so文件时,会调用init init_array段的函数,是整个so最先被调用的函数

#include <stdio.h>
#include <stdint.h>

void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
  unsigned int i;
  uint32_t v0 = v[0], v1 = v[1], sum = 0, delta = 0x67e885e5;
  for (i = 0; i < num_rounds; i++)
  {
    sum += delta;
    v0 += (((v1 << 3) ^ (v1 >> 6)) + v1) ^ (sum + key[sum & 3]);
    v1 += (((v0 << 2) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 8) & 3]);
  }
  v[0] = v0;
  v[1] = v1;
}

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
  unsigned int i;
  uint32_t v0 = v[0], v1 = v[1], delta = 0x67e885e5, sum = delta * num_rounds;
  for (i = 0; i < num_rounds; i++)
  {
    v1 -= (((v0 << 2) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 8) & 3]);
    v0 -= (((v1 << 3) ^ (v1 >> 6)) + v1) ^ (sum + key[sum & 3]);
    sum -= delta;
  }
  v[0] = v0;
  v[1] = v1;
}

int main()
{
  uint32_t v[2] = {0xad05217d, 0xf7c0c3e2};
  uint8_t k[16] = {0x54, 0x68, 0x31, 0x73, 0x49, 0x73, 0x41, 0x6e, 0x33, 0x61, 0x73, 0x79, 0x43, 0x68, 0x61, 0x6c};
  unsigned int r = 32;
  decipher(r, v, (uint32_t *)k);
  printf("%s\n", v);
  return 0;
}

nd_xt3a!
最终flag:VNCTF{u_Know_@ndro1d_And_xt3a!}

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

MiniVNCTF
/archives/minivnctf
作者
Britney
发布于
2025-12-07
许可协议
CC BY-NC-SA 4.0

评论