buu题解-[GWCTF 2019]xxor

打开题目:查壳,无壳

拖入ida中打开,shift+f12查找字符串

 找到可疑字符串:Congratulations

交叉引用找到相关函数

_int64 __fastcall main(int a1, char **a2, char **a3)
{
  int i; // [rsp+8h] [rbp-68h]
  int j; // [rsp+Ch] [rbp-64h]
  __int64 v6[6]; // [rsp+10h] [rbp-60h] BYREF hidword与loword的含义
                 //                           c语言怎么取高四位和第四位方法
                 //                           dword含义
                 //                           
  __int64 v7[6]; // [rsp+40h] [rbp-30h] BYREF

  v7[5] = __readfsqword(0x28u);
  puts("Let us play a game?");
  puts("you have six chances to input");
  puts("Come on!");
  memset(v6, 0, 40);
  for ( i = 0; i <= 5; ++i )
  {

    printf("%s", "input: ");
    a2 = (v6 + 4 * i);                          // 输入六个数据,每个数据占四字节
                                                // v6+0:第一个数据开始位置
                                                // v6+4:第二个数据开始位置
                                                // 因为v6是8字节数据两个数据合在一起是v6[0]
                                                // 以此类推
                                                // 
    __isoc99_scanf("%d", a2);
  }
  memset(v7, 0, 40);
  for ( j = 0; j <= 2; ++j )                    // 每次取出两个数据处理
  {
    dword_601078 = v6[j];                       // 即一个为v6[j]的低位
                                                // 一个为v6[j]的高位
    dword_60107C = HIDWORD(v6[j]);              // 取高四位字节,即dword(注:dword是四字节,两个字,word是两字节,一个字)
    a2 = &unk_601060;
    sub_400686(&dword_601078, &unk_601060);     // 在对取出的V6[j]的低位数据和高位数据进行处理加密
    LODWORD(v7[j]) = dword_601078;              // v7低四位是处理加密后的v6的低四位的值
    HIDWORD(v7[j]) = dword_60107C;              // 高四位等于v6加密后的高四位
  }
  if ( sub_400770(v7, a2) != 1 )                // 得到V7
                                                // a2 = E0F30FD5,
                                                //  a1 = 20CAACF4,
                                                //  a3 = 5C50D8D6,
                                                //  a4 = 2652626477,
                                                //  a5 = 9E1BDE2D,
                                                //  a0 = -20B71082
  {
    puts("NO NO NO~ ");
    exit(0);
  }
  puts("Congratulation!\n");
  puts("You seccess half\n");
  puts("Do not forget to change input to hex and combine~\n");
  puts("ByeBye");
  return 0LL;
}

分析函数:

1.首先是一个for循环输入6个数据,每个数据占四个字节

2.然后又是一个for循环,分别用dword_601078和dword_60107C取v6每个值的低四位数据和高四位数据(因为 v6[6]是int64(8字节)类型,而上一个循环每次输入的是四字节数据,所以数据在v6中的排列如下

   v6[0](8字节)v6[1]v6[2]
四字节数据1四字节数据2四字节数据3四字节数据4四字节数据5四字节数据6

)

3.取数据如何实现的呢?dword只能存储两个字也就是四个字节,所以能够实现取v6的低四位,取高四位数据使用了HIDWORD函数,函数可以实现截取数据的高四位(具体用法可以参考一位大佬的博客HIDWORD函数与LODWIORD函数

4.然后将V6第四位数据的地址传到sub_400686函数中,再将加密后的数据赋给v7,再将v7传入sub_400770函数中,跟进此函数查看

__int64 __fastcall sub_400770(_DWORD *a1)
{
  if ( a1[2] - a1[3] == 2225223423LL
    && a1[3] + a1[4] == 4201428739LL
    && a1[2] - a1[4] == 1121399208LL
    && *a1 == -548868226
    && a1[5] == -2064448480
    && a1[1] == 550153460 )
  {
    puts("good!");
    return 1LL;
  }
  else
  {
    puts("Wrong!");
    return 0LL;
  }
}

 很明显的用z3约束求解器求解方程,得到v7,即加密后的v6 数据,此处放出求解v7的代码

from z3 import *

a0= Real('a0')
a1= Real('a1')
a2 = Real('a2')
a3 = Real('a3')
a4 = Real('a4')
a5 = Real('a5')

s = Solver()



s.add( a2 - a3 == 2225223423)
s.add(a3 + a4 == 4201428739)
s.add(a2- a4 == 1121399208)
s.add(a0 == -548868226)
s.add(a5 == -2064448480)
s.add(a1 == 550153460)

if s.check() == sat:
    result = s.model()
print(result)
# print(s.model())

此时我们跟进查看加密v6的函数:

_int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
{
  __int64 result; // rax
  unsigned int v3; // [rsp+1Ch] [rbp-24h]
  unsigned int v4; // [rsp+20h] [rbp-20h]
  int v5; // [rsp+24h] [rbp-1Ch]
  unsigned int i; // [rsp+28h] [rbp-18h]

  v3 = *a1;
  v4 = a1[1];
  v5 = 0;
  for ( i = 0; i <= 63; ++i )
  {
    v5 += 1166789954;
    v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
    v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
  }
  *a1 = v3;
  result = v4;
  a1[1] = v4;
  return result;
}

此处将v6 的低四位数据和高四位数据分别赋给v3和v4然后经过一系列加密过程。分析完后写解密脚本,解出后还要转换成字符串哦

#include<stdio.h>
int main(){
int i,j;
unsigned int  v3,v4,v5;
int a2[4]={2,2,3,4};                                              
 int a1[6]={-548868226,550153460,3774025685,1548802262,2652626477,-2064448480};
for(i=0;i<=4;i+=2){

  v3 = a1[i];                                    
  v4 =a1[i+1];                                  
  v5 =1166789954*64 ;
  for ( j = 0; j <= 63; ++j )
  {v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
    v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
    v5 -= 1166789954; 
  }
  a1[i]=v3;
  a1[i+1]=v4;
 }
 for(i=0;i<6;i++){
 	printf("%x",a1[i]);
 }
	return 0;
}

学到的点:

  • 根据变量类型和输入数据类型判断输入数据在变量中存储方式,如输入的是int 型变量是int64型。
  • dword可以实现取数据的低四位
  • HIDWORD函数与LODWORD函数分别取数据的高四位和低四位,HIWORD和LOWORD函数实现取数据的高两位和低两位
  • c语言如何实现获取低四位和高四位
    public int getHeight4(byte data){//获取高四位
        int height;
        height = ((data & 0xf0) >> 4);
        return height;
    }
      
    public int getLow4(byte data){//获取低四位
        int low;
        low = (data & 0x0f);//0x0f(00001111)
        return low;    
    }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值