XDCTF2015_re100
去年做的一道 CTF,清理文档
0x01 The .init and .fini Sections
参考下面链接:
http://www.ru.j-npcs.org/usoft/WWW/www_debian.org/Documentation/elf/node3.html
简单说一下,即.init中的指令,在main()函数之前执行,.fini中的指令,在main()函数返回后执行;
一段代码验证之:
#include <stdio.h>
void my_init() __attribute__((constructor));
void my_fini() __attribute__((destructor));
void my_init()
{
printf("init?\n");
}
void my_fini()
{
printf("fini?\n");
}
int main()
{
printf("I'm in main()\n");
return 0;
}
输出结果:
ez[@ubuntu](http://my.oschina.net/u/555627):~/xdctf$ ./init
init?
I'm in main()
fini?
下面链接,有更详细介绍:
DT_INIT:ELF loaded时执行
DT_INIT_ARRAY:其中的函数被顺序执行,完成main()前的初始化操作,通常存放于.init_array段
DT_FINI:ELF unloaded时或进程结束时执行
DT_FINI_ARRAY:与DT_INIT_ARRAY类似,用于main()后扫尾
0x02 IDA静态分析
用IDA打开re100,发现是一个Linux x86_64程序;没有main()函数,可能编译时修改了入口函数,可参考:
没有_start函数,但发现有一处start函数与_start函数类似,猜测ld时被修改,具体可参考:
http://eli.thegreenplace.net/2012/08/13/how-statically-linked-programs-run-on-linux/
我们平常所说的__libc_start_main()函数,其实在_start()中被调用:
.text:0000000000400590 public _start
.text:0000000000400590 _start proc near
.text:0000000000400590 xor ebp, ebp
.text:0000000000400592 mov r9, rdx
.text:0000000000400595 pop rsi
.text:0000000000400596 mov rdx, rsp
.text:0000000000400599 and rsp, 0FFFFFFFFFFFFFFF0h
.text:000000000040059D push rax
.text:000000000040059E push rsp
.text:000000000040059F mov r8, offset __libc_csu_fini
.text:00000000004005A6 mov rcx, offset __libc_csu_init
.text:00000000004005AD mov rdi, offset main
.text:00000000004005B4 call ___libc_start_main
.text:00000000004005B9 hlt
.text:00000000004005B9 _start endp
比较一下正常的_start与该题目中的start函数发现,入口被从main()修改为了sub_4008E1():
### 修改后 start
.text:000000000040053E push rsp
.text:000000000040053F mov r8, offset nullsub_1
.text:0000000000400546 mov rcx, offset loc_400AA0
.text:000000000040054D mov rdi, offset sub_4008E1
.text:0000000000400554 call ___libc_start_main
### 正常的 _start
.text:000000000040059E push rsp
.text:000000000040059F mov r8, offset __libc_csu_fini
.text:00000000004005A6 mov rcx, offset __libc_csu_init
.text:00000000004005AD mov rdi, offset main
.text:00000000004005B4 call ___libc_start_main
继续分析sub_4008E1()函数,其开始处有ptrace()的简单反调试;如果需要gdb调试,则nop之即可,这里静态分析暂不管它;
初步分析此函数功能,首先栈上有两个字符串,分别为命名为g_key和g_enc:
0x0601280 g_key "\\|Gq\\@?BelTtK5L`\\|D`d42;"
0x6012A0 g_enc ";%#848N!0Z?7'%23]/5#1\"YX"
sub_4008E1()函数将用户输入的12个字符flag与g_key进行一系列异或运算后,与g_enc进行比较,如果相等,则输入的flag验证通过;
如果这样做,得出的结果永远是错的,其实题目也有个Hint,Don’t believe your eyes..因为我们忽略了.init_array和.fini_array中的代码,而这两段中的函数,对g_key和异或算法均有影响;由上面收集的资料可知,其分别会在sub_4008E1()函数之前和之后执行;
.init_array:0000000000601000 ; =============================================================
.init_array:0000000000601000
.init_array:0000000000601000 ; Segment type: Pure data
.init_array:0000000000601000 ; Segment permissions: Read/Write
.init_array:0000000000601000 ; Segment alignment 'qword' can not be represented in assembly
.init_array:0000000000601000 _init_array segment para public 'DATA' use64
.init_array:0000000000601000 assume cs:_init_array
.init_array:0000000000601000 ;org 601000h
.init_array:0000000000601000 off_601000 dq offset sub_400600 ; DATA XREF: .text:0000000000400AB1 o
.init_array:0000000000601008 dq offset sub_400669
.init_array:0000000000601008 _init_array ends
.init_array:0000000000601008
.fini_array:0000000000601010 ; ===============================================================
.fini_array:0000000000601010
.fini_array:0000000000601010 ; Segment type: Pure data
.fini_array:0000000000601010 ; Segment permissions: Read/Write
.fini_array:0000000000601010 ; Segment alignment 'qword' can not be represented in assembly
.fini_array:0000000000601010 _fini_array segment para public 'DATA' use64
.fini_array:0000000000601010 assume cs:_fini_array
.fini_array:0000000000601010 ;org 601010h
.fini_array:0000000000601010 off_601010 dq offset sub_4005E0 ; DATA XREF: .text:0000000000400AB9 o
.fini_array:0000000000601018 dq offset sub_400787
.fini_array:0000000000601018 _fini_array ends
.fini_array:0000000000601018
分析发现sub_400669()函数对g_key进行了异或操作,也就是我们用来异或的g_key并不是内存中的内容:
size_t sub_400669()
{
size_t result; // rax@1
int i; // [sp+Ch] [bp-14h]@2
result = dword_601340;
if ( dword_601340 != 1 )
{
dword_601340 = 1;
for ( i = 0; ; ++i )
{
result = strlen(key_str_1);
if ( i >= result )
break;
key_str_1[i] ^= 6u;
}
}
return result;
}
而sub_400787()函数中才是我们真正需要破解的代码:
char *sub_400787()
{
char *result; // rax@13
signed int v1; // [sp+8h] [bp-18h]@9
int i; // [sp+Ch] [bp-14h]@1
unsigned int j; // [sp+Ch] [bp-14h]@4
unsigned int k; // [sp+Ch] [bp-14h]@9
for ( i = 0; i < strlen(key_str_1); ++i )
char_array_24[i] = key_str_1[i] ^ char_array_16[i - 12 * (((0x0AAAAAAAAAAAAAAABLL * i) >> 64) >> 3)];
sub_4006D5(char_array_24, 24, 12);
for ( j = 0; j <= 0x17; ++j )
{
if ( char_array_24[j] <= 31 )
char_array_24[j] += 32;
}
v1 = 1;
for ( k = 0; ; ++k )
{
result = k;
if ( k > 0x17 )
break;
if ( char_array_24[k] != key_str_2[k] )
v1 = 0;
}
if ( v1 )
{
result = output_;
if ( output_ )
{
output_[15] = '!';
puts(output_);
exit(0);
}
}
return result;
}
根据算法逆推脚本如下:
def get_flag(g_enc, g_key):
flag = []
size = 24
for i in xrange(0, size, 1):
if ( ord(g_enc[i]) - 0x20) <= 0x1F:
flag.append(ord(g_enc[i])-0x20)
else:
flag.append(ord(g_enc[i]))
for i in xrange(0,size/2,1):
flag[i] ^= flag[17-i]
flag[17-i] ^= flag[i]
flag[i] ^= flag[17-i]
for i in xrange(0,size,1):
flag[i] = flag[i%(size/2)] ^ (ord(g_key[i])^6)
for i in xrange(0,size/2,1):
flag[i] = chr(flag[i])
return "".join(flag[:size/2])
if __name__ == '__main__':
g_key = "\\|Gq\\@?BelTtK5L`\\|D`d42;"
g_enc = ";%#848N!0Z?7'%23]/5#1\"YX"
flag = get_flag(g_enc, g_key)
print flag
ez[@ubuntu](http://my.oschina.net/u/555627):~/xdctf$ python get_flag.py
U'Re_AwEs0Me
根据提示结果均为小写,最终flag为:XDCTF{u’re_awes0me}
XDCTF2015_re100的更多相关文章
随机推荐
- jquery 学习(一):jQuery 简介
jQuery 库 - 特性: jQuery 是一个 JavaScript 函数库. jQuery 库包含以下特性: html 元素获取, html 元素操作, css 操作, html 事件函数, J ...
- 时间序列(六): 炙手可热的RNN: LSTM
目录 炙手可热的LSTM 引言 RNN的问题 恐怖的指数函数 梯度消失* 解决方案 LSTM 设计初衷 LSTM原理 门限控制* LSTM 的 BPTT 参考文献: 炙手可热的LSTM 引言 上一讲说 ...
- python assert使用说明
python assert断言的作用 python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假. assert断言语句的语法格式 判断a与1.b是否一致,msg类似备注 ...
- [CodeForces - 447E] E - DZY Loves Fibonacci Numbers
E DZY Loves Fibonacci Numbers In mathematical terms, the sequence Fn of Fibonacci numbers is define ...
- 把旧系统迁移到.Net Core 2.0 日记(9) -- T4 Template
想着用T4 Template 自动生成代码,省了功夫. 发现T4 Template 挺笨的. 我开始这样写是会报错的 <# var modualName = "CRM" ...
- Java Web(四) 过滤器Filter
Filter概述 Filter意为滤镜或者过滤器,用于在Servlet之外对request或者response进行修改.Filter提出了过滤链的概念.一个FilterChain包括多个Filter. ...
- sql取大的一个值
select b.*, a.recid, a.keyno from product b, (select pcode, ...
- QuickStart系列:docker部署之MongoDB
MongoDB[1] 是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB[2] 是一个介于关系数据库和非关系数据库之间的产品, ...
- 外部点击链接,登陆后,直接跳转到该链接(过滤器 + Cookie实现)
一.web.xml (1)指定过滤的Servlet类 (2)配置过滤规则,过滤以.mail结尾的链接 <?xml version="1.0" encoding="U ...
- 十六. Python基础(16)--内置函数-2
十六. Python基础(16)--内置函数-2 1 ● 内置函数format() Convert a value to a "formatted" representation. ...