就是mark一下里面smc
解法
做的时候可以直接锁定加密部分sub_4014FA函数
size_t __cdecl sub_4014FA(char *a1, char *a2)
{
int v2; // eax@3
int v3; // ebx@5
int v4; // eax@5
int v5; // ebx@7
int v6; // eax@7
size_t result; // eax@17
signed int v8; // [sp+10h] [bp-18h]@1
size_t v9; // [sp+10h] [bp-18h]@15
int j; // [sp+14h] [bp-14h]@15
signed int i; // [sp+18h] [bp-10h]@1
int v12; // [sp+1Ch] [bp-Ch]@1
v12 = 0;
v8 = 4 * strlen(a1) / 3;
for ( i = 0; i < v8; ++i )
{
if ( i & 3 )
{
if ( ((((i >> 32) >> 30) + i) & 3) - ((i >> 32) >> 30) == 1 )
{
v3 = 16 * a1[v12 - 1] & 0x30;
v4 = v12++;
a2[i] = byte_405020[v3 | (a1[v4] >> 4)];
}
else if ( ((((i >> 32) >> 30) + i) & 3) - ((i >> 32) >> 30) == 2 )
{
v5 = 4 * a1[v12 - 1] & 0x3C;
v6 = v12++;
a2[i] = byte_405020[v5 | (a1[v6] >> 6)];
}
else
{
a2[i] = byte_405020[a1[v12 - 1] & 0x3F];
}
}
else
{
v2 = v12++;
a2[i] = byte_405020[(a1[v2] >> 2)];
}
}
if ( strlen(a1) % 3 == 1 )
{
a2[v8] = byte_405020[16 * a1[v12 - 1] & 0x30];
a2[v8 + 1] = 61;
a2[v8 + 2] = 61;
}
else if ( strlen(a1) % 3 == 2 )
{
a2[v8] = byte_405020[4 * a1[v12 - 1] & 0x3C];
a2[v8 + 1] = 61;
}
a2[strlen(a2)] = 0;
v9 = strlen(a2);
for ( j = 0; ; ++j )
{
result = v9 - 1;
if ( (v9 - 1) <= j )
break;
a2[j + 1] ^= a2[j]; //每个字符异或和前一位异或
}
return result;
}
改表的base64
文件32位跟加密后数据对比
字符异或得到
DnY0m19iAgArMKjSP2Uvme8wOzb0iD==
从网上找个base64解码,套脚本就好
题目的解法很简单
关于smc可以看到
int __cdecl sub_4017AA(char a1)
{
char *Str; // ST00_4@4
char *MaxCount; // [sp+4h] [bp-200h]@3
int DstBuf; // [sp+Eh] [bp-1F6h]@1
__int16 v5; // [sp+12h] [bp-1F2h]@1
int v6; // [sp+3Ch] [bp-1C8h]@1
CHAR Filename; // [sp+40h] [bp-1C4h]@1
char Str1; // [sp+144h] [bp-C0h]@1
char Buf[60]; // [sp+1A8h] [bp-5Ch]@1
unsigned int mum; // [sp+1E4h] [bp-20h]@1
FILE *v11; // [sp+1E8h] [bp-1Ch]@4
char *v12; // [sp+1FCh] [bp-8h]@1
v12 = &a1;
sub_401EE0();
puts("Sorroundings...Weird..");
mum = 0;
memset(Buf, 0, sizeof(Buf));
memset(&Str1, 0, 0x64u);
memset(&Filename, 0, 0x104u);
DstBuf = 0;
v6 = 0;
memset((&v5 & 0xFFFFFFFC), 0, 4 * (((&DstBuf + -(&v5 & 0xFFFFFFFC) + 50) & 0xFFFFFFFC) >> 2));
puts("I see!It's not my fault!Wrong is the world!");
puts("So..Now I should give a shot to fix it!");
************************************************************************
scanf("%u", &mum); //输入一个数字
if ( mum > 0x20000 ) //判断输入数字大小
sub_40178C();
getchar(); //吃掉回车
sub_401460(mum); //关键
puts("And then,a shiny explosion!");
fgets(Buf, 59, iob);
Buf[strlen(Buf) - 1] = 0;
if ( strlen(Buf) != 22 )
sub_40178C();
**************************************************************************
puts("Seems I have passed a test.");
sub_4014FA(Str, MaxCount);
GetModuleFileNameA(0, &Filename, 0x104u);
v11 = fopen(&Filename, "rb");
fseek(v11, -32, 2);
fread(&DstBuf, 0x20u, 1u, v11);
fclose(v11);
if ( !strcmp(&Str1, &DstBuf) )
{
puts("Congratulations!");
puts("The flag is hgame{your input string + your input num}");
puts("e.g:hgame{aaaaaaaaaa111}");
}
else
{
printf("But Failed..Finally");
}
return 0;
}
进入sub_401460函数
BOOL __cdecl sub_401460(unsigned int a1)
{
DWORD flOldProtect; // [sp+14h] [bp-14h]@1
unsigned int v3; // [sp+18h] [bp-10h]@1
unsigned int v4; // [sp+1Ch] [bp-Ch]@1
flOldProtect = 0;
VirtualProtect(TopLevelExceptionFilter, 0x4000u, 0x40u, &flOldProtect);//更改页属性
v4 = a1 >> 3;
v3 = a1 & 7;
*(TopLevelExceptionFilter + (a1 >> 3)) ^= 1 << (a1 & 7);
return VirtualProtect(TopLevelExceptionFilter, 0x4000u, flOldProtect, &flOldProtect); //基址是TopLevelExceptionFilter ,0x401000
}
做的时候并没有太注意,没有详细分析。当喵说了安卓的smc的时候才知道这个也是更改了某个地址。
*(TopLevelExceptionFilter + (a1 >> 3)) ^= 1 << (a1 & 7);
[地址基址 + (输入的数字右移三位)] 和输入数字的后三位异或]
7 bin 0111
后边3位可以与某个地址异或,剩下的几位作为地址偏移来改变某一地方。
查看反汇编发现了此处跳传导致sub_4014FA函数没有参数进栈。
这两个参数的作用是显示出
怎么能保证正常跳转呢?这就需要使用上面分析的,将jmp short loc_4018F5改为jmp short loc_4018E5
jmp short loc_4018F5的机器码为 EB 15;JMP的机器码为EB,15为偏移。
0x15 = 0x4018F5 - 0x4018DE - jmp长度(2byte)
那么跳到 loc_4018E5就是
x4018E5-0x4018DE-0x2=0x5
所以输入数字最低三位应为100
要修改的字节的地址是0x4018DF ,所以输入的数字:
mum=(0x8df<<3) + 0x4 = 0x46FC=18172
(当然可以直接在文件中更改
这样这个题目也算是完整了:
Byt3_H4cker_sho0O0o0t!
总结:和安卓的那个smc很像,基本可以归为一类但实现smc的方法明显安卓的要复杂不少。