jeb反编译
s 是用户输入,s1 是加密后flag: Ku@'G_V9v(yGS
传入Native函数 CheckFlag
IDA分析Native函数
注意这里有一个陷阱,CheckFlag有静态注册函数和动态注册函数,会执行动态注册的函数。
a2 == 93 只会走sub_1028
sub_1028 看着花里胡哨的,实际执行结果就是 a1/a2;
代码可以直接复制到idea,调试跟着过一遍就清楚了。
int __fastcall sub_1028(unsigned int a1, unsigned int a2)
{
int v2; // r12
unsigned int v3; // r3
int v4; // r2
int result; // r0
v2 = a1 ^ a2;
v3 = 1;
v4 = 0;
if ( (a2 & 0x80000000) != 0 )
a2 = -a2;
if ( (a1 & 0x80000000) != 0 )
a1 = -a1;
if ( a1 >= a2 )
{
while ( a2 < 0x10000000 && a2 < a1 )
{
a2 *= 16;
v3 *= 16;
}
while ( a2 < 0x80000000 && a2 < a1 )
{
a2 *= 2;
v3 *= 2;
}
while ( 1 )
{
if ( a1 >= a2 )
{
a1 -= a2;
v4 |= v3;
}
if ( a1 >= a2 >> 1 )
{
a1 -= a2 >> 1;
v4 |= v3 >> 1;
}
if ( a1 >= a2 >> 2 )
{
a1 -= a2 >> 2;
v4 |= v3 >> 2;
}
if ( a1 >= a2 >> 3 )
{
a1 -= a2 >> 3;
v4 |= v3 >> 3;
}
if ( !a1 )
break;
v3 >>= 4;
if ( !v3 )
break;
a2 >>= 4;
}
}
result = v4;
if ( v2 < 0 )
return -v4;
return result;
}
算法还原
public static void main(String[] args) {
String tag = "Ku@'G_V9v(yGS";
String aLjavaLangStrin_0 = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
char[] chars = new char[tag.length()];
//可显示字符范围是32--126
for (int i = 0; i < tag.length(); i++) {
//根据可见字符的范围推断 除93的商 要么是0 要么是1
int temp = tag.charAt(i) - 32 + 64 - aLjavaLangStrin_0.charAt(i);
if (temp <= 126 && temp > 32){ //32是空格不能等于32
chars[i] = (char) temp;
} else {
chars[i] = (char) (temp + 93);
}
}
System.out.println(chars);
}
运行结果:
CISCN{GJ5728}