@romangol
2014-10-31T10:34:49.000000Z
字数 3094
阅读 2914
writeup
CTF
首先需要修复PE头,从MS Dos Header指向PE header的偏移应该是0xE8,此外PE header头部的magic number 从"PE\FF\0"改成"PE\0\0",完成修复 其次分析程序,程序输入9个数,但是只需要前面三个数进行一个运算,满足相关条件,中间三个数为80 94 98,最后三个数无关,然后打印出flag只取前面三个数
写代码搜索:
#include <stdio.h>
int main( int argc, char *argv[] )
{
for ( size_t i = 0; i < 0x100000; ++i )
{
for ( size_t j = 0; j < 0x100000; ++j )
{
size_t k = (i ^ j) + 4;
if ( i * j * k / 0xb == 0x6a && (i + j + k) % 100 == 0x22 )
{
printf( "%d %d %d\n", i, j, k );
//return 1;
}
}
}
return 0;
}
有多解,然后程序中还有一个限制条件检查,逻辑比较繁琐,我们直接测试了多个解发现15 6 13这一组是正确解
flag为: jlflag{15613abc}
程序非常可爱的去检查IsDebugPresent,如果存在Debug才会执行,所以需要用非隐藏版的调试器执行或者手工patch
程序接下来会读取keyfile,读取出来的内容用strol函数(16进制编码)转换成特定的值和0x19310918 异或,得到的值符合程序中固定的值即可,但是这个题目明显的存在多解,因为strol可以接受各种格式的输入,例如0xFFFFFFFF和FFFFFFFF都是转换成统一的值,另外还有前面插入多余的空格等等。
最后正确的flag应该是: 0x181f0d1f
是一道自修改代码的题目,会把0x00422000上的代码做一个运算然后去执行
简单的写了一个搜索程序,特征是要求搜索出来最后一个字节是0xc3也就是retn
#include <stdio.h>
unsigned char t( unsigned short c, size_t num )
{
unsigned int result = 1;
for ( size_t i = 0; i < num; ++i )
{
result = c * result % 0x5ED;
}
return result & 0xFF;
}
unsigned short Table[] =
{
0x00F9, 0x02C3, 0x034B, 0x0149, 0x04E7, 0x02C3, 0x012E, 0x0570, 0x0543, 0x0001, 0x02C3, 0x059C, 0x018C, 0x02BF, 0x054E, 0x0009, 0x0009, 0x0543, 0x0000, 0x056E, 0x008B, 0x055B, 0x018C, 0x0234, 0x05D9, 0x0009, 0x0009, 0x0395, 0x01A6, 0x0570, 0x0000, 0x0000, 0x0000, 0x0000, 0x046B, 0x0294, 0x0102, 0x044E, 0x0000, 0x046B, 0x0499, 0x027D, 0x0382, 0x05B6, 0x046B, 0x01FE, 0x01FE, 0x050D, 0x0390, 0x046B, 0x0471, 0x037F, 0x02CA, 0x0499, 0x046B, 0x027D, 0x033C, 0x0453, 0x01A9, 0x046B, 0x0543, 0x043D, 0x0073, 0x043D, 0x05D2, 0x02CA, 0x0570, 0x02C3, 0x012E, 0x0570, 0x0417, 0x045D, 0x0417, 0x005F, 0x0417, 0x00A1, 0x00FC, 0x0563, 0x012E, 0x005F, 0x0552, 0x012F, 0x01F7, 0x03C7, 0x0417, 0x0481, 0x0001, 0x0417, 0x02B2, 0x0001, 0x0417, 0x00A1, 0x00FC, 0x0563, 0x012E, 0x0223, 0x03FF, 0x0035, 0x0262, 0x03FF, 0x033F, 0x0262, 0x0552, 0x012F, 0x012E, 0x0469, 0x01FE, 0x0035, 0x0036, 0x0491, 0x0564, 0x0035, 0x03FF, 0x01B6, 0x0009, 0x0108, 0x0035, 0x012E, 0x0330, 0x0481, 0x046B, 0x05B0, 0x0000, 0x031E, 0x0000, 0x046B, 0x0035, 0x0035, 0x00EC, 0x0000, 0x0481, 0x0009, 0x03E0, 0x04A8, 0x01FE, 0x00EC, 0x0000, 0x03FF, 0x0168, 0x03FB, 0x02B2, 0x0032, 0x01DF, 0x01B1
};
unsigned char TableNew[0x90];
int main( int argc, char *argv[] )
{
for ( size_t input = 0; input < 0x100; ++input )
{
for ( size_t i = 0; i < 0x90; ++i )
{
TableNew[i] = t( Table[i], input );
}
if ( TableNew[0x90 - 1] == 0xc3 )
{
for ( size_t i = 0; i < 0x90; ++i )
printf("%02x ", TableNew[i] );
printf( "\n---%d---\n", input );
}
}
return 0;
}
搜索出来以后,发现当input取233的时候,解出来的第一个字节0x55符合push ebp特征,所以选择它,然后解出来的代码中有硬编码的flag
jlflag{L04e_3389_admin}
首先发现是梆梆加固的apk,利用百度研究员贾志军开发的ZJDroid(http://blog.csdn.net/androidsecurity/article/details/38121585)进行脱壳,得到一个dex文件,发现里面去exec了一个findstr的native code,于是逆向分析该binary,该binary接受的是输入字符串的逆序,然后将输入字符串做了两个变换A和B,再和binary内部一固定字符串做两个变换C和D之后进行比较。C和D变换比较复杂,但是我们使用了IDA动态调试直接拿到了固定字符串做完C和D变换后的值,无视逆向,然后写出代码
#include <stdio.h>
int main( int argc, char *argv[] )
{
char str[] = "+nv|ai|KivO:w:vr";
char new_str[] = "+nv|ai|KivO:w:vr";
new_str[5] = str[4];
new_str[6] = str[5];
new_str[8] = str[6];
new_str[9] = str[7];
new_str[10] = str[8];
new_str[13] = str[9];
new_str[14] = str[10];
new_str[4] = str[11];
new_str[7] = str[12];
new_str[11] = str[13];
new_str[12] = str[14];
for ( size_t i = 0; i < 16; ++i )
{
new_str[i] -= 10;
}
for ( size_t i = 0; i < 16; ++i )
{
str[15 - i] = new_str[i];
}
puts(str);
return 0;
}
运行得到flag是
hEll0_Arm_W0rld!