打开题目:查壳,无壳
拖入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; }