无壳,载入IDA.
搜索找到main函数开始分析.
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char v4[16]; // [rsp+0h] [rbp-4A0h] BYREF
char v5[16]; // [rsp+10h] [rbp-490h] BYREF
char v6[16]; // [rsp+20h] [rbp-480h] BYREF
char v7[16]; // [rsp+30h] [rbp-470h] BYREF
char v8[112]; // [rsp+40h] [rbp-460h] BYREF
char v9[1000]; // [rsp+B0h] [rbp-3F0h] BYREF
unsigned __int64 v10; // [rsp+498h] [rbp-8h]
v10 = __readfsqword(0x28u);
puts("[sign in]");
printf("[input your flag]: ");
__isoc99_scanf("%99s", v8);
sub_96A(v8, v9);
__gmpz_init_set_str(v7, "ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16LL);
__gmpz_init_set_str(v6, v9, 16LL);
__gmpz_init_set_str(v4, "103461035900816914121390101299049044413950405173712170434161686539878160984549", 10LL);
__gmpz_init_set_str(v5, "65537", 10LL);
__gmpz_powm(v6, v6, v5, v4);
if ( (unsigned int)__gmpz_cmp(v6, v7) )
puts("GG!");
else
puts("TTTTTTTTTTql!");
return 0LL;
}
这段代码是一个使用GMP(GNU Multiple Precision Arithmetic Library)库实现的简单加密挑战程序。它模拟了一个“签到”流程,要求用户输入一个标志(flag),然后验证这个标志是否符合特定的加密条件。下面是对代码的详细解释:
变量声明
v4
,v5
,v6
,v7
,v8
,v9
是字符数组(在栈上分配),但主要用于存储GMP库中的大整数(mpz_t类型)的字符串表示。GMP库使用字符串来初始化或导出大整数的值。v10
是一个unsigned __int64
类型的变量,用于存储一个与浮点状态寄存器相关的值,这通常用于在函数开始时保存状态,并在函数结束时恢复,以确保浮点运算的一致性。然而,在这个程序中,它似乎没有被进一步使用。程序流程
- 打印提示信息:
- 使用
puts
函数打印"[sign in]"。- 使用
printf
函数打印"[input your flag]: ",提示用户输入一个标志。- 读取用户输入:
- 使用
__isoc99_scanf
函数读取最多99个字符的用户输入,并存储在v8
中。这里假设用户输入的是一个十六进制字符串。- 处理用户输入:
- 调用
sub_96A(v8, v9)
函数,是将用户输入的十六进制字符串转换为某种形式,并存储在v9
中。- 初始化大整数:
- 使用
__gmpz_init_set_str
函数初始化并设置大整数v7
、v6
、v4
、v5
。这些大整数分别对应于不同的值:
v7
:一个硬编码的十六进制字符串表示的大整数。v6
:用户输入(经过sub_96A
处理)的十六进制字符串表示的大整数。v4
:一个硬编码的十进制字符串表示的大整数,用作模数。v5
:另一个硬编码的十进制字符串表示的大整数,用作指数(在模幂运算中)。- 模幂运算:
- 使用
__gmpz_powm
函数计算v6
的v5
次方模v4
的结果,并将结果存回v6
。这个运算用于加密或验证用户输入的标志是否符合特定的数学关系。- 比较并输出结果:
- 使用
__gmpz_cmp
函数比较v6
和v7
。如果它们不相等,输出"GG!";否则,输出"TTTTTTTTTTql!"。这表明如果用户的输入经过处理后满足特定的加密条件(即,加密后的值等于硬编码的值v7
),则验证成功。关键点
- 这个程序的核心在于模幂运算和比较操作。模幂运算是密码学中常见的操作,用于加密、解密和验证等操作。
- 用户输入的标志需要经过
sub_96A
函数的处理才能用于模幂运算,这表明可能存在某种形式的预处理或解密步骤。- 程序中的
v4
(模数)和v5
(指数)是硬编码的,而v7
(目标值)也是硬编码的,这意味着用户必须输入一个特定的值(或其加密形式),以使得v6
经过模幂运算后等于v7
。- 这是一个典型的加密挑战,其中
v7
是挑战的目标值,用户需要通过分析或猜测来找到正确的输入值。
很明显这是一个RSA加密.
知识点可以参考下面这篇文章:
我们已知E ,N,密文(v7),我们只需要将明文求出便可以得到flag值.
公式:
求N | N= p * q ;p,q为质数 |
求L | L=lcm(p-1,q-1) ;L为p-1、q-1的最小公倍数 |
求E | 1 < E < L,gcd(E,L)=1;E,L最大公约数为1(E和L互质) |
求D | 1 < D < L,E*D mod L = 1 |
求明文首先我们需要求D,求D需要知道E和L,而L=(q-1)*(p-1),而N=p*q.
p和q通过在在线网站分解一下.
开始构造exp.
import binascii
import gmpy2
p=282164587459512124844245113950593348271
q=366669102002966856876605669837014229419
e=65537
c=0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n=p*q
l=(p-1)*(q-1)
d=gmpy2.invert(e,l)
m=gmpy2.powmod(c,d,n)
print(binascii.unhexlify(hex(m)[2:]).decode(encoding="utf-8"))
拿到flag,游戏结束.
标签:__,加密,v6,char,SignIn1,gmpz,v7,SUCTF2019 From: https://blog.csdn.net/alwtj/article/details/142206764