ISCC 2016 逆向部分 writeup
Posted GlodsNow
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ISCC 2016 逆向部分 writeup相关的知识,希望对你有一定的参考价值。
ISCC2016 逆向部分
by GoldsNow
做了这套题目感觉涨了不少的姿势。。渣渣就只能够用渣渣的方法
Help me
描述:I’ve got a difficult task and I can’t solve it. I need your help!
思路:爆破
ELF64位的程序,直接在IDA中打开,可以看出来思路应该是比较清晰
先点进去main函数来进行分析。
for ( i = 0; i <= 15; ++i )
{
if ( !(v11 & 1) )
++v5;
v11 >>= 1;
}
先对这个一段代码进行分析,经过位运算,来判断二进制数字有多少个 0
很明显 这里只需要三个 0
这里的MD5是个比较坑的地方,C语言并没有自带的库, 也不知道它到底进行的是什么。 只知道他是与 unk_6020A0 来比较的 有尝试 对这个地址的数据进行 MD5的解密,可惜最终是失败了的。
换一个思路,我们可以看到这里的 word_602080 经过了异或运算 然后 byte_6020C0 减去 这个的值然后输出最终的flag 所以可以从这个角度来解决题目, 这里面值有 V10也就是输入的那一个数字是不知道的, 可以通过暴力破解来实现。
我在做题目的时候用了C语言来判断, 判断第五个字母是不是‘{’
附上我的c程序可以参考一下。
unsigned char a[]={0x34,0x12,0x78,0x56,0xBC,0x9A,0xFF,0xED,0xEF,0xBE,0x7F,0x22,0xC3,0x90,0x76,0x82,0xAD,0x99,0x2E,0x14,0x7C,0x80};
unsigned char b[]={0x22,0x3F,0xD8,0xEB,0xCC,0xD2,0x42,0x87,0x61,0x75,0x01,0x09,0x27,0xF9,0xDC,0xE8,0x16,0xFC,0x5F,0x89,0xB3,0xFD};
__int16 c[6]={0x3412,0x7856,0xbc9a,0xffed,0xefbe,0x7f22};
__int16 d[6];
__int16 x1=0,x2=0xffff,x=0;
for(int i=0;i<=15;i++) // 三重for循环将 v10的可能性都列出来了
for(int j=i+1;j<=15;j++)
for(int m=j+1;m<=15;m++)
{
x2==0xffff;
x1=(__int16)(pow(2,i)+pow(2,j)+pow(2,m));
x=x2-x1; //这三行是为了得到V10的可以理解一下
for(int n=0;n<=5;n++)
{
d[n]=c[n]^x;
a[2*n]=d[n]>>8;
a[2*n+1]=( __int8) d[n];
}
if(b[4]-a[4]==‘{‘) //如果是‘{‘就输出 可能的flag
{
printf("%x ",x);
for(int i=0;i<22;i++)
printf("%c",b[i]-a[i]);
printf("\n");
}
}
破解加密软件
描述:我方截获了敌方的一款加密程序和一段密文,尝试通过对此程序进行分析实现对密文的解密,解密后明文的32位小写MD5值作为flag提交。
思路:扣出程序中所包含的一个加密解密系统,得到密钥 解密
吾爱破解对于这个题目也有比较详细的解题过程 链接
通过OD载入然后搜索里面的字符串可以发现 程序有两个功能,一个就是原题所给的 输入字符串就加密,其实里面还有一个程序就是 通过给与密钥就能够加密与解密
通过修改跳转,或者修改 call 的内容等等其他 方法能够让程序运行到那一段 这样就好办了。但是 还不知道密钥是什么。
想法是密钥肯定会在 初始的加密程序中引用
对程序进行单步跟踪。一步一步运行 到达一定地方的时候堆栈中就出现了如下可惜的八位数字,并且这个不会随着你的输入而改变数字,猜测其为密钥
果然没错 一下子就出来了
这里有一个地方就是 直接用OD跑出来的值会有一个空格多出来也不知道是为什么。
菜鸟的逆袭
描述:”小明是个游戏新手,一天他闲得无聊去找基友打L4D2,基友嫌他太菜,不愿带他,无奈小明百般纠缠,便给了他一个程序,并且告诉他:“如果你能得到正确答案,我就把我毕生混野绝学传授给你。”聪明的你能帮助小明得到正确的答案吗?
测试环境:干净的WinXP SP3”
找不到动态调试的软件。只能够静态分析,用IDA打开。
可以通过提示 推断出来 这里有两个词,分别是DEAD和BEEF
正好属于A-F 因为是A-F 属于0-F的范围 都符合16进制的值。所以上面的V9就是0xdeadbeef或者说0xDEADBEEF
通过将dword_10F80-dword_10F90与V9异或输出,能够得到 一串看起来很像flag的值但是 要靠程序接下来分析 将字符串进行了转化
orPh0fh!:hlghnoCgalF
这样转化一下就出来了,,是不是很简单,,,但是要去想到却很难。。
矛盾
描述:To be or not to be, that is the question.
思路 去除TLS,暴力
参考资料 http://www.2cto.com/Article/201303/197705.html
IDA载入
找到TLScallback 在010中打开它用00填充此部分 保存文件就能够进入程序的主函数部分了,但是还是不能够得到flag 有点小郁闷
通过查看字符串来寻找有没有弹出窗口,运气不错发现一个弹出窗口。
并且在上面也出现了flag的字样。
函数的上有几个 sub_4385FF 推测他用的就是memset 将目标的地址段 值置零。所以这里就会使最终的flag
最后处理 的是直接打开OD跳转到相关的语段 跑一下就出来了。
Anti
描述:Every technique has its anti.
这个题目就是 反调试,,绕过dll文件中的对调试器和模拟器的检测。。
操作方法,具体就不介绍了,就是在OD中 一步一步,对于有些 call 直接就nop掉 一些明显要推出的函数就强制跳转或者也nop了
进入主程序之后,难度就会明显下降
很容易就能够找到主要的那个对比的地址, 最后有一段看起来很复杂的加密方法,,,,分析半天没分析出来,后来一看就32位的,,就想到了可能是用了MD5加密方法,,最终在XMD5 一下子就出来flag 了。
GoGoGo
描述:Mission is a go.
这个题目用了GO语言。问了很多人,都说是用动态分析做出来了,但是我最后是通过静态分析,很容易就做出来了。
IDA的分析是非常规的。 只能靠猜
v38 = "Please input : ";
v39 = off_4DC4C0[1];
v40 = 0LL;
v41 = 0LL;
if ( &v30 == -88 )
LODWORD(v40) = 0;
v42 = &v40;
v43 = 1;
v44 = 1;
v30 = &unk_4A10A0;
v31 = &v38;
sub_41FA10(&v42, a2, a3, v3);
v4 = v42;
v5 = v42;
*v42 = v32;
++v5;
*v5 = v33;
++v5;
v30 = v4;
v31 = v43;
v32 = v44;
sub_42C510(v5, &v34, v6, v7, v8, v9);
sub_400C00(v5, &v34);
v36 = v30;
v37 = v31;
v32 = &unk_4D73F0;
v33 = *(&off_4D73E0 + 1);
v10 = &off_4D73E0 + 2;
sub_446A70(&v34, (&off_4D73E0 + 2), v11, v30, v12, v13);
v16 = v34;
v36 = v34;
v37 = v35;
if ( v35 != 38 || (v30 = v34, v31 = 38, sub_400CB0(&v34, v10, v14, v34, v15), v32 != 1) )
{
v38 = "Wrong!!!";
v39 = off_4DCCE0[1];
v40 = 0LL;
v41 = 0LL;
if ( &v30 == -88 )
LODWORD(v40) = 0;
v42 = &v40;
v43 = 1;
v44 = 1;
v30 = &unk_4A10A0;
v31 = &v38;
sub_41FA10(&v42, v10, v14, v16);
v24 = v42;
v25 = v42;
*v42 = v32;
++v25;
*v25 = v33;
v30 = v24;
v31 = v43;
v32 = v44;
result = sub_42C510((v25 + 1), &v34, v26, v27, v28, v29);
}
else
{
v38 = "Congratz!!";
v39 = off_4DB7A0[1];
v40 = 0LL;
v41 = 0LL;
if ( &v30 == -88 )
LODWORD(v40) = 0;
v42 = &v40;
v43 = 1;
v44 = 1;
v30 = &unk_4A10A0;
v31 = &v38;
sub_41FA10(&v42, v10, v14, v16);
v17 = v42;
v18 = v42;
*v42 = v32;
++v18;
*v18 = v33;
v30 = v17;
v31 = v43;
v32 = v44;
result = sub_42C510((v18 + 1), &v34, v19, v20, v21, v22);
}
截图太累 直接把代码复制了,,通过对比 可以看出 这个 ‘sub_42C510’ 才是输出的结束语句
input 那边还需要一个读取字符的语句 就猜测是 ‘sub_446A70’ 这语段是输出语段。
主要起作用的当然是 if语句里的那个 sub_400CB0 了
这里有一个 字符转化和一个内存中的数据很可疑,,刚开始以为是输入的语句经过处理变成这样,但是实际上我错了。是这个内存中的 数据 经过这个处理会出现一段base64加密过的数据。。
附上代码
int b[52]={0xA5,0xD6,0x87,0x86,0xA5,0x33,0x37,0x03,0xE4,0x75,0xE4,0xB6,0x95,0xA7,0xC6,0xD6,0xE4,0x44,0x94,0x53,0xE4,0xA6,0xB6,0x53,0xD4,0x23,0xD4,0x77,0xD4,0xA7,0x46,0xB6,0xA5,0x74,0x55,0x13,0xD4,0xA6,0x36,0x87,0x95,0x75,0x55,0x43,0x95,0xA6,0x15,0x03,0x95,0x33,0x03,0xD3};
for(int j=0;j<52;j++)
{
printf("%c",(16*b[j]|b[j]>>4));
}
就是这么简单,,然后将这个进过base64解密一下就出来了 我也觉的很意外。
以上是关于ISCC 2016 逆向部分 writeup的主要内容,如果未能解决你的问题,请参考以下文章