buureservewp(2)

[GUET-CTF2019]re

这道题挺简单的
查壳,upx,然后脱壳,用shift+f12找字符串,找到主函数
在这里插入图片描述
发现correct的条件与sub_4009ae函数有关,点进去

{
  if ( 1629056 * *a1 != 166163712 )
    return 0LL;
  if ( 6771600 * a1[1] != 731332800 )
    return 0LL;
  if ( 3682944 * a1[2] != 357245568 )
    return 0LL;
  if ( 10431000 * a1[3] != 1074393000 )
    return 0LL;
  if ( 3977328 * a1[4] != 489211344 )
    return 0LL;
  if ( 5138336 * a1[5] != 518971936 )
    return 0LL;
  if ( 7532250 * a1[7] != 406741500 )
    return 0LL;
  if ( 5551632 * a1[8] != 294236496 )
    return 0LL;
  if ( 3409728 * a1[9] != 177305856 )
    return 0LL;
  if ( 13013670 * a1[10] != 650683500 )
    return 0LL;
  if ( 6088797 * a1[11] != 298351053 )
    return 0LL;
  if ( 7884663 * a1[12] != 386348487 )
    return 0LL;
  if ( 8944053 * a1[13] != 438258597 )
    return 0LL;
  if ( 5198490 * a1[14] != 249527520 )
    return 0LL;
  if ( 4544518 * a1[15] != 445362764 )
    return 0LL;
  if ( 3645600 * a1[17] != 174988800 )
    return 0LL;
  if ( 10115280 * a1[16] != 981182160 )
    return 0LL;
  if ( 9667504 * a1[18] != 493042704 )
    return 0LL;
  if ( 5364450 * a1[19] != 257493600 )
    return 0LL;
  if ( 13464540 * a1[20] != 767478780 )
    return 0LL;
  if ( 5488432 * a1[21] != 312840624 )
    return 0LL;
  if ( 14479500 * a1[22] != 1404511500 )
    return 0LL;
  if ( 6451830 * a1[23] != 316139670 )
    return 0LL;
  if ( 6252576 * a1[24] != 619005024 )
    return 0LL;
  if ( 7763364 * a1[25] != 372641472 )
    return 0LL;
  if ( 7327320 * a1[26] != 373693320 )
    return 0LL;
  if ( 8741520 * a1[27] != 498266640 )
    return 0LL;
  if ( 8871876 * a1[28] != 452465676 )
    return 0LL;
  if ( 4086720 * a1[29] != 208422720 )
    return 0LL;
  if ( 9374400 * a1[30] == 515592000 )
    return 5759124 * a1[31] == 719890500;
  return 0LL;

发现这么多数字都是v4数组里面的,不过关键少了个a1[6],然后a1[17]跟a1[16]位置反了,写个脚本吧:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a[31] = {166163712,731332800,357245568,1074393000,489211344,518971936,406741500,294236496,177305856,650683500,298351053,386348487,438258597,249527520,445362764,981182160,174988800,493042704,257493600,767478780,312840624,1404511500,316139670,619005024,372641472,373693320,498266640,452465676,208422720,515592000,719890500};
    int b[31] = {1629056,6771600,3682944,10431000,3977328,5138336,7532250,5551632,3409728,13013670,6088797,7884663,8944053,5198490,4544518,10115280,3645600,9667504,5364450,13464540,5488432,14479500,6451830,6252576,7763364,7327320,8741520,8871876,4086720,9374400,5759124};
    char flag[31];
    for(int i=0;i<31;i++){
        flag[i] = a[i] / b[i];
    }
      for(int i=0;i<31;i++){
        printf("%c",flag[i]);
    }
    return 0;
}

然后最终的flag,少了第六位的值,那就一个数字一个字母的试呗,最终得到flag
在这里插入图片描述
e跟6之间加一个1就对了

[WUSTCTF2020]level1

这一题也挺简单的
ida里面,shift + f12查看字符串,找到flag,进入函数
在这里插入图片描述
可以看到是有20次循环,然后打开给出的txt文本,发现只有19个数字,那么第一位给0

0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000

然后看着伪代码,写成c语言的形式:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a[20] = {0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000};
    char flag[19];
    for(int i=1;i<=19;i++){
        if(i&1){
        printf("%c",(a[i]>>i));
        }
    else{
        printf("%c",(a[i]/i));
            }
    }
    return 0;
}

在这里插入图片描述

[SUCTF2019]SignIn

进入ida找到main函数
在这里插入图片描述

__gmpz_init_set_str 函数:
*int mpz_init_set_str (mpz_t rop, const char str, int base) [Function]
作用就是将 str 字符数组以 base 指定的进制解读成数值并写入 rop 所指向的内存。该程序通过调用这个函数来实现数据的初始化赋值。
__gmpz_powm 函数:
void mpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const mpz_t mod) [Function]
计算 base 的 exp 次方,并对 mod 取模,最后将结果写入 rop 中
这种计算跟rsa一样

我们需要理解一下rsa的加密解密过程

在这里插入图片描述

图中的E是公钥(E和 φ(N)互为质数),N是公共模数(质数 P 、Q相乘得到N),MOD就是模运算

在这里插入图片描述

图中的D是私钥(私钥由这个公式计算得出E * D % φ(N) = 1),N是公共模数(质数 P
、Q相乘得到N),MOD就是模运算,φ(N)是欧拉函数(由这个公式计算得出φ(N) = (P-1)(Q-1))。

所以:

密文:ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
N:103461035900816914121390101299049044413950405173712170434161686539878160984549
e:65537

然后根据N求出q和p
在这里插入图片描述
再用工具求出d
在这里插入图片描述
然后写python代码:

# 无注释
# 因为你啥都不会,快去学!!!
import gmpy2
import libnum
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
d = 91646299298871237857836940212608056141193465208586711901499120163393577626813
m = gmpy2.powmod(c,d,n)
print(libnum.n2s(int(m)))

在这里插入图片描述
也可以先把m的值转为十六进制,再把十六进制转为字符串

m=185534734614696481020381637136165435809958101675798337848243069
十六进制:73756374667b50776e5f405f68756e647265645f79656172737d
字符串:suctf{Pwn_@_hundred_years}
因为函数一开始就是把输入的字符串转为十六进制的,然后算出来的又是十进制,所以就逆回去

libnum库:
数字型(不论是十六进制还是十进制)与字符串之间的转换:

> import libnum
s="flag{52Hertz_is_caiji}"
print(libnum.s2n(s))
#164587995846501346531234137103678929624631014312713866001802621
import libnum
n=0x666c61677b54656c6c4772696e5f69735f636169446f5f38657d
print (libnum.n2s(n))
#flag{TellGrin_is_caiD_o8e}

还有二进制与字符串的转换:

import libnum
s='TellGrin'
print(libnum.s2b(s))
#0101010001100101011011000110110001000111011100100110100101101110
import libnum
s = '0101010001100101011011000110110001000111011100100110100101101110'
print(libnum.b2s(s))
#TellGrin

[MRCTF2020]Transform

这题也挺简单的
看主函数:
在这里插入图片描述
首先flag长度为33.
byte_414040数组的值已经知道了,然后跟dword_40F040数组进行异或。
然后以dword_40F040数组为flag数组的下标等于byte_414040数组,就能解出来了
脚本:

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

int main(void)
{
    char flag[33];
    char a[33] = {0x67,0x79,0x7B,0x7F,0x75,0x2B,0x3C,0x52,0x53,0x79,0x57,0x5E,
		0x5D,0x42,0x7B,0x2D,0x2A,0x66,0x42,0x7E,0x4C,0x57,0x79,0x41,0x6B,
		0x7E,0x65,0x3C,0x5C,0x45,0x6F,0x62,0x4D};
    char b[33] = {0x9, 0x0A, 0x0F, 0x17, 0x7, 0x18, 0x0C, 0x6, 0x1, 0x10, 0x3, 0x11, 0x20,
		0x1D, 0x0B, 0x1E, 0x1B, 0x16, 0x4, 0x0D, 0x13, 0x14, 0x15, 0x2, 0x19,
	0x5, 0x1F, 0x8, 0x12, 0x1A, 0x1C, 0x0E};
    char c[33] = "gy{u+<RSyW^]B{-*fB~LWyAk~e<\EobM";
    char d[33] = {0};
    for(int i = 0;i<33;i++){
        d[i] = a[i] ^ b[i];
        flag[b[i]] = d[i];
    }
    for(int i = 0;i<33;i++){

    }
    printf("%s",flag);
    return 0;
}


[WUSTCTF2020]level2

这道题。。。。。。怎么说呢。。。。。
脱完壳,看ida,我以为是个陷阱,没想到就直接是个flag
好吧,没想到,反正主函数我也没找到。。。。。。。
在这里插入图片描述

[ACTF新生赛2020]usualCrypt

看主函数
在这里插入图片描述
byte_40E0E4:输入的字符串经过加密后进行比较,是则对
在这里插入图片描述
进入加密函数,发现是base64加密,再看看密码表
在这里插入图片描述
加密的开始,有个关于密码表的函数,看一下
在这里插入图片描述

首先两个数组,看后俩位,简单记作【AA,A0】
v1 = aa的第六位
aa第六位=a0第六位
a0第六位=v1
=================
v1 = aa的第七位
aa第七位=a0第七位
a0第七位=v1
最后那个while语句控制循环次数,交换到第14位停止

然后看两个密码表:

a0:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
aa:LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
如果a0不接着aa的话,那么位数不足
那么两个交换的也就是:GHIJKLMNO跟QRSTUVWXY换
最后的密码表:
ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/

变化的密码表知道了,然后解密之后的字符串还会经历一个函数:大小写转换函数:
sub_401030
在这里插入图片描述
大小写转换的伪代码,分析:

在区间(97,122)小写字母会-32,变成大写
在区间(65,90)大写字母会+32,变成小写
我觉得第二个if语句少了个else,不然我就能理解的更快了。。。。(LOBYTE前边)加个else

在这里插入图片描述
然后跟一个数组进行一对一比较,而那个数组也给了
在这里插入图片描述
那么思路来了:

①先大小写转换
②再解密

脚本①:

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

int main()
{
    char a[35]="zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9";
    for(int i =0;i<35;i++){
    if ( a[i] < 97 || a[i] > 122 )
      {	
    if ( a[i] < 65 || a[i] > 90 ){}

    else a[i] = a[i] + 32;
      }
      else
      {
        a[i] = a[i] - 32;
      }
    }
    printf("%s",a);
	return 0;
}
//ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9

脚本②:最后用了别人的base64,换了个表,懒得自己弄了。。。。。
在这里插入图片描述
至于最后为什么解密字符串第一个多了一个Z:
在这里插入图片描述
原理跟上面那个AA和A0数组的情况一样,7A的文本是:z
上下两个数组连起来的,所以多了一个z,也就是Z。。。。。。。

Youngter-drive

脱壳,打开ida查看main函数
在这里插入图片描述
这是一个多线程,首先有两个线程:hObject和v2
先进入hObject:
在这里插入图片描述
一个函数和一个减减
先看函数:
在这里插入图片描述
首先排除不是26个字母的范围了
再看减减:
1D是29,我猜flag长度30
在这里插入图片描述
再进入第二个线程:
在这里插入图片描述
只有一个减减
继续往下看,还有一个sub_411190函数:
在这里插入图片描述
估计就是经过加密后的函数跟off_418004数组进行对比,相同则输出,且是30的长度,那就确定了,falg长度是30,但上面那个是29,感觉。。。。。。不妙
目前出现过两个数组:off_418000和off_418004,找出来:
在这里插入图片描述
所以,总结一下:

两个线程,一个加密然后减减,一个只减减,而减的数字是29
说明只有奇数进行加密,偶数不变
加密函数:
先判断输入的值是否是大小写
判断之后,匹配两个数组的值是否一样,如果004数组的值跟000数组的值一样,找000数组那个值的下标
如果是大写:下标+96,小写:下标+38
为什么在脚本里是大写+96,而伪代码里面是大写+38,那是因为,脚本里面判断大小写的是a数组(加密过后的),伪代码里面是flag,还没有加密过,所以反了

脚本(因为没有除26个字母之外的字符,所以就简化了):

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{

    char flag[29];
    char a []="TOiZiZtOrYaToUwPnToBsOaOapsyS";
    char b[]="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
    for(int i=0;i<29;i++){
        int j=0;
        if(i % 2 == 0){
            flag[i] = a[i];
            i++;
        }
        while(a[i]!= b[j]){
            j++;
        }
    if ( a[i] >= 65 && a[i] <= 90 ){
        flag[i] = j + 96;
      }
      else
      {
        flag[i] = j + 38;
      }
    //for(int i =0;i<30;i++){

    //}
    }
    printf("%s",flag);
	return 0;
}


最后给了一个长度位29的flag,少了一位,猜出来是E
中间有个堆栈不平衡的知识点:
F5 sub_411940函数失败
在这里插入图片描述
我们点击菜单栏>>Options>>General>>勾选Stack points
在这里插入图片描述
发现飘红的上方的sp值都是负的,我们用Alt+K改为正的值或者改为0x00
在这里插入图片描述
在这里插入图片描述
就能查看伪代码了
之后关于加密函数我又分析了一波,不想让自己半知半解

a = b[flag[1]-38]
逆向求flag:
先求出来 b = a Ascii值的那一位,然后位数+38
自己太菜了,这么简单的逻辑还有想半天哎~😓

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值