VCTF纳新赛reverse算法解析

题目概况

本次题目是来自VCTF纳新赛的题目

链接
https://ctf.venomsec.com/#/indexicon-default.png?t=N7T8https://ctf.venomsec.com/#/index本次的文案是以reverse方向为主的,所以就在这两个题目上下手

先来看第一个题目

ezre

先进行查壳操作,可以看到是64位的

打开前的准备

用ida打开文件之后,进入以下界面

同样的,按F5进入mian函数界面

点击mian进入主函数,得到以下代码

代码如下:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  size_t v3; // rax
  const char *v4; // rax
  size_t v6; // [rsp+8h] [rbp-8h]

  __isoc99_scanf("%21s", byte_41E0);
  v6 = strlen(byte_41E0);
  v3 = strlen(aThi51sKey);
  sub_1492(&unk_4160, aThi51sKey, v3);
  sub_16B3(&unk_4160, byte_41E0, v6);
  v4 = (const char *)sub_1249(byte_41E0, (unsigned int)v6);
  if ( !strcmp(s1, v4) )
    puts("success!");
  else
    puts("fail!");
  return 0LL;
}

代码分析

大致思路

首先,在代码的最开头,我们通过伪C代码的分析可以知道:

第7行先进行代码的输入(最多能输入21个字符),将这段字符的位置传给byte_41E0的位置

第8行和第9行分别计算两个位置所带的字符串的长度

第10行到第12行对上面的两个位置以及unk_4160进行某些操作

现在的主要思路就是在第10到第12行的位置的分许中来进行

内部函数的分析

第10行

点击进去进行分析

代码如下:

unsigned __int64 __fastcall sub_1492(__int64 a1, __int64 a2, unsigned __int64 a3)
{
  __int64 v3; // kr00_8
  char v5; // [rsp+27h] [rbp-99h]
  int i; // [rsp+28h] [rbp-98h]
  int j; // [rsp+28h] [rbp-98h]
  int v8; // [rsp+2Ch] [rbp-94h]
  __int64 v9[17]; // [rsp+30h] [rbp-90h] BYREF
  unsigned __int64 v10; // [rsp+B8h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  v8 = 0;
  memset(v9, 0, 128);
  for ( i = 0; i <= 127; ++i )
  {
    *(_BYTE *)(i + a1) = i;
    *((_BYTE *)v9 + i) = *(_BYTE *)(i % a3 + a2);
  }
  for ( j = 0; j <= 127; ++j )
  {
    v3 = v8 + *(unsigned __int8 *)(j + a1) + *((char *)v9 + j);
    v8 = (((HIDWORD(v3) >> 25) + (_BYTE)v8 + *(_BYTE *)(j + a1) + *((_BYTE *)v9 + j)) & 0x7F) - (HIDWORD(v3) >> 25);
    v5 = *(_BYTE *)(j + a1);
    *(_BYTE *)(j + a1) = *(_BYTE *)(v8 + a1);
    *(_BYTE *)(a1 + v8) = v5;
  }
  return v10 - __readfsqword(0x28u);
}

我们主要来考虑一下for循环的问题

第一个for循环的代码逻辑

首先它将0到127位置上的值都变为了i(一一对应的,第i个位置就是i)

也就可以理解为将这些值初始化的一个操作

紧接着,从a2取地址值将位置进行操作传给v9   

a3是从main函数里面传输进去的

要注意的是,这里的a2不是字符,是a2的地址a3是mian函数里面的字符串长度

同样的,看到i%a3的计算,我们不难看出

for ( i = 0; i <= 127; ++i )
  {
    *(_BYTE *)(i + a1) = i;
    *((_BYTE *)v9 + i) = *(_BYTE *)(i % a3 + a2);
  }

这里的rc4加密算法的模已经被更改了

(正常的rc4的模为256,而这里为128,更改过后的要注意变化)

总体来说,分为了以下几步:

进入加密算法函数看加密的过程进行分析

base64加密过程

点进去base64加密过程的函数中,我们可以看到这样的一串

这是一个base64算法的加密过程

点击下面的a123456789xyza进去,我们可以得到这样的一串字符串

这就是经过更改的表

注意:这一串字符串并不是原本的base64解码的表格

原本的表格是这样的

由此可知,我们的数表在这里进行了更改

对该代码进行base64解码

在线工具推荐使用赛博厨子 网址

From Base64, To Hex - CyberCheficon-default.png?t=N7T8https://cyberchef.org/#recipe=From_Base64('0123456789XYZabcdefghijklABCDEFGHIJKLMNOPQRSTUVWmnopqrstuvwxyz%2B/%3D',true,false)To_Hex('0x%20with%20comma',0)&input=M3BuMUVrOTJobUFFZzM4RVhNbjk5SjlZQmY4PQ截图如下:

获得的结果:

0x0f,0x3c,0x41,0x75,0x72,
0x42,0x53,0x06,0x5d,0x4c,
0x32,0x1d,0x2a,0x5c,0x49,
0x26,0x22,0x4b,0x69,0x22

如果不嫌麻烦,可以自行创建一个脚本进行解码操作,不过进行的步骤有点复杂,我之后会来开一期进行讲解

将上述的地址的字符进行输出,代码如下:

#include <stdio.h>
#include <string.h>

int main()
{
    char a[] = {0x0f, 0x3c, 0x41, 0x75, 0x72, 0x42, 0x53, 0x06, 0x5d, 0x4c, 0x32, 0x1d, 0x2a, 0x5c, 0x49, 0x26, 0x22, 0x4b, 0x69, 0x22};
    
    for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++) {
        printf("%c", a[i]);
    }

    return 0;
}

输出结果如下:

<AurBS]L2*\I&"Ki"

不过官方的wp的解答的情况是这样的

\x0f<AurBS\x06]L2\x1d*\\I&"Ki"

那就以官方的为准

同时,进行rc4的算法解密

import base64
import string

def rc4_init(s,key,length):
	k = []
	for i in range(128):
		k.append('0')
	for i in range(128):
		s[i] = i
		k[i] = key[i%length]
	j = 0
	for i in range(128):
		j = (j+s[i]+ord(k[i]))%128
		#print j
		tmp = s[i]
		s[i] = s[j]
		s[j] = tmp


def rc4_crypt(s,data,length):
	i = 0
	j = 0
	data1 = ''
	for k in range(length):
		i = (i+1)%128
		j = (j+s[i])%128
		tmp = s[i]
		s[i] = s[j]
		s[j] = tmp
		t = (s[i]+s[j])%128
		data1 += chr(data[k]^s[t])
	return data1


str1 = "3pn1Ek92hmAEg38EXMn99J9YBf8="

string1 = "0123456789XYZabcdefghijklABCDEFGHIJKLMNOPQRSTUVWmnopqrstuvwxyz+/="
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

data = base64.b64decode(str1.translate(str.maketrans(string1,string2)))
print(data)
key = "Thi5_1S_key?"
s = []
for i in range(128):
	s.append(0)
rc4_init(s,key,len(key))
data1 = rc4_crypt(s,data,len(data))
print(data1)
#
\x0f<AurBS\x06]L2\x1d*\\I&"Ki"'
flag{Simple_rEvErse}

flag{Simple_rEvErse}

  • 46
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值