非常坑爹的一道题目,看似非常简单,实则有套路

链接: http://pan.baidu.com/s/1i4XLCd3 密码:9zho

为了练手 我会写出三种解法,包括 结合ascii码值范围的爆破,动态调试解法,静态调试解法

(感谢我xx学长的支持和某位网友的writeup)

1.首先拿到该程序,丢进ida会发现这是个elf程序,程序主体看起来也很简单,在ubuntu下也能正常跑起来

int __cdecl main()
{
int v0; // eax@1
char *v1; // edx@2
int v2; // ecx@3
int v4; // [sp+1Ch] [bp-10h]@4 printf("%s\nPlease input your flag:", off_8049900);
__isoc99_scanf("%s", &byte_8049908);
v0 = off_8049900 - (char *)main;
if ( off_8049900 > (char *)main )
{
v1 = (char *)main;
do
{
v2 = (unsigned __int8)*v1++;
v0 = v2 ^ (v0 >> ) ^ * v0;
}
while ( v1 != off_8049900 );
}
v4 = v0;
if ( __PAIR__((unsigned __int8)(byte_8049909 ^ BYTE1(v4)), (unsigned __int8)(byte_8049908 ^ v0)) != word_80498F0
|| ((unsigned __int8)byte_804990A ^ BYTE2(v0)) != byte_80498F2
|| (BYTE3(v0) ^ (unsigned __int8)byte_804990B) != byte_80498F3
|| ((unsigned __int8)v0 ^ (unsigned __int8)byte_804990C) != byte_80498F4
|| (BYTE1(v4) ^ (unsigned __int8)byte_804990D) != byte_80498F5
|| (BYTE2(v0) ^ (unsigned __int8)byte_804990E) != byte_80498F6
|| (BYTE3(v0) ^ (unsigned __int8)byte_804990F) != byte_80498F7
|| ((unsigned __int8)v0 ^ (unsigned __int8)byte_8049910) != byte_80498F8
|| (BYTE1(v4) ^ (unsigned __int8)byte_8049911) != byte_80498F9
|| (BYTE2(v0) ^ (unsigned __int8)byte_8049912) != byte_80498FA
|| (BYTE3(v0) ^ (unsigned __int8)byte_8049913) != byte_80498FB
|| ((unsigned __int8)dword_8049914 ^ (unsigned __int8)v0) != byte_80498FC
|| (*(_WORD *)((char *)&dword_8049914 + ) ^ *(_WORD *)((char *)&v4 + )) != word_80498FD
|| (BYTE3(dword_8049914) ^ BYTE3(v0)) != byte_80498FF )
{
puts("You are wrong");
}
else
{
puts("You are right");
}
return ;
}

2.结合汇编语言,对程序可以做一个大致的分析,第二个if的判断是分别将输入的字符串的每一位和v4/v0(32位)的第一,二,三,四个字节做异或并将结果和0x80498f0起始处的字符串做比较,只有16位全相等时才会输出正确

3.瞄了一眼,v4和v0的值发现和输入字符串无关,应该是个固定值,而v4=v0对应的汇编语言是mov edx,eax,所以正常的想法是用gdb在0x08048416处下断点

.text:080483EB                 mov     eax, ebx
.text:080483ED sub eax, offset main
.text:080483F2 cmp ebx, offset main
.text:080483F8 jbe short loc_8048416
.text:080483FA mov edx, offset main
.text:080483FF nop
.text:
.text: loc_8048400: ; CODE XREF: main+64j
.text: mov ecx, eax
.text: sar ecx, 1Bh
.text: shl eax,
.text: xor eax, ecx
.text:0804840A movzx ecx, byte ptr [edx]
.text:0804840D add edx,
.text: xor eax, ecx
.text: cmp edx, ebx
.text: jnz short loc_8048400
.text:
.text: loc_8048416: ; CODE XREF: main+48j
.text: mov edx, eax
.text: xor dl, ds:byte_8049908
.text:0804841E cmp dl, byte ptr word_80498F0
.text: mov [esp+1Ch], eax
.text: jnz loc_8048566
.text:0804842E movzx edx, byte ptr [esp+1Dh]
.text: mov ecx, edx
.text: xor cl, ds:byte_8049909
.text:0804843B cmp cl, byte ptr word_80498F0+
.text: jnz loc_8048566
.text: movzx ecx, byte ptr [esp+1Eh]
.text:0804844C mov ebx, ecx
.text:0804844E xor bl, ds:byte_804990A
.text: cmp bl, byte_80498F2
.text:0804845A jnz loc_8048566

4.如果你的思路和我一样,那么恭喜你入套了,不过还是先这样走完

5.用gdb下断点后可以得到eax的值,如图为:0xd90c5525

6.于是我尝试写了这样一个python脚本:

a=[0x18,0x5b,0xbf,0x38,0x34,0x5a,0x99,0x4d,0x2e,0x73,0xbb,0x4e,0x23,0x76,0x9f,0x3]
b=[0x25,0x55,0x0c,0xd9]
c=''
for i in range(16):
d=i%4
c+=(chr(a[i]^b[d]))
print c

7.当然你得到的只会是乱码。。。

8.好吧,现在是早上01:43:32我就不废话了,我还要睡觉呢!错误的原因在于第一个if语句是对text段的读操作,并对读到的值进行一系列的运算操作,从main函数一直读到0x0804872A,当然也会读到你下断点的地方,而据网上资料所讲b *0x 操作是将相应处内存改为0xcc,这样一来你得到的eax和edx的值就会不对,那该怎么办呢

解法一:动态调试的方法

这期间我犯了很多很多的错误

错误一:我分别用了 b *0x08048418 if $eip==0x08048146//r 和b *0x080483fa//r//b *08048418 if $edx==$dbx这两种方法

错误的原因在于理解错了breakpoint指令的意思  我以为b if 是时时监控 条件成立就下断点  实际上是运行到断点处才判断。。

如果是犯同样错误的人自己理解吧,这样是不行的

错误二:watch $eip==0x08048418      也是错的 具体原因我还没有查

直接写出最终解法吧:内存访问监控  涉及到的gdb指令是awatch(awatch是读写断点,内存被读或着写时都会断。而rwatch是读时断,watch是写时断。)

我这里用到的是awatch

指令序列为awatch *0x08048148//r//info b//d 1//s//s//...//b *0x08048148//c

还有其他很多方法:b *0x80483fa//r//d 1//awatch *0x8049908//c

最简单的方法:awatch *0x80498f0

这样一来就能得到正确的eax值,再结合最开始写的脚本就可以得到flag

方法二:爆破

这样需要结合flag的格式进行一定的手动猜测,一个简单python脚本最没技术含量的吧:

a=[0x18,0x5b,0xbf,0x38,0x34,0x5a,0x99,0x4d,0x2e,0x73,0xbb,0x4e,0x23,0x76,0x9f,0x3]
b='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTTUVWXYZ0123456789{}_()='
for i in range(4):
for j in range(0x00,0xff):
for k in range(4):
d=chr(j^a[i+4*k])
if d not in b:
break
if k==3:
print '\n'
print i,hex(j)
for l in range(4):
print chr(j^a[i+4*l]),

方法三:静态调试

写脚本直接访问文件对应地址的数据进行计算,这里计算得到的都是eax寄存器的值

分别用c和python写了两个脚本,两种方法

先看c的,直接访问源文件,这里有一个问题,文本要以rb方式打开,r不行,因为

以“r”方式读取,系统只读出ascii中可显示字符;如果不可显示(控制字符),系统会把它滤掉。但是“rb”的方式则不会。:

#include<stdlib.h>
#include<stdio.h> void main()
{
FILE *fp;
fp=fopen("C:\\Users\\tLOMO\\Desktop\\Elfcrackme2","rb");
int i=0x37a; //(main)0x80483b0~0x804872a地址之间的二进制文件内容的长度0x37A
if(fp!=NULL)
{
int m,n;
int a;
for(n=;n<0x3b0;n++)//main从0x3b0开始
{
fgetc(fp);
}
for(m=;m<0x37a;m++)
{
a=fgetc(fp);
i=a^(i>>)^(*i);
}
printf("value of eax is:%x",i);
}
else
{
printf("the file is blank");
}
fclose(fp);
system("pause");
}

再来看python的,这里也遇到了一个比较严重的问题,不注意的话可能不会发现,

因为源程序是c语言,int默认为有符号32位,那么c>>27,如果是负数的话,高位会补f而不是0,而python是个弱类型语言,64位python,int为64位,所以会出问题,所以这里要做一个转换:

a='''55 89 E5 57 56 53 83 E4  F0 83 EC 20 A1 00 99 04
08 C7 04 24 F0 86 04 08 89 44 24 04 E8 8F FF FF
FF C7 44 24 04 08 99 04 08 C7 04 24 0B 87 04 08
E8 BB FF FF FF 8B 1D 00 99 04 08 89 D8 2D B0 83
04 08 81 FB B0 83 04 08 76 1C BA B0 83 04 08 90
89 C1 C1 F9 1B C1 E0 05 31 C8 0F B6 0A 83 C2 01
31 C8 39 DA 75 EA 89 C2 32 15 08 99 04 08 3A 15
F0 98 04 08 89 44 24 1C 0F 85 38 01 00 00 0F B6
54 24 1D 89 D1 32 0D 09 99 04 08 3A 0D F1 98 04
08 0F 85 1F 01 00 00 0F B6 4C 24 1E 89 CB 32 1D
0A 99 04 08 3A 1D F2 98 04 08 0F 85 06 01 00 00
0F B6 7C 24 1F 0F B6 1D 0B 99 04 08 31 FB 3A 1D
F3 98 04 08 0F 85 EC 00 00 00 0F B6 1D 0C 99 04
08 31 C3 3A 1D F4 98 04 08 0F 85 D7 00 00 00 0F
B6 1D 0D 99 04 08 31 D3 3A 1D F5 98 04 08 0F 85
C2 00 00 00 0F B6 1D 0E 99 04 08 31 CB 3A 1D F6
98 04 08 0F 85 AD 00 00 00 0F B6 1D 0F 99 04 08
31 FB 3A 1D F7 98 04 08 0F 85 98 00 00 00 0F B6
1D 10 99 04 08 31 C3 3A 1D F8 98 04 08 0F 85 83
00 00 00 0F B6 1D 11 99 04 08 31 D3 3A 1D F9 98
04 08 75 72 0F B6 1D 12 99 04 08 31 CB 3A 1D FA
98 04 08 75 61 0F B6 1D 13 99 04 08 31 FB 3A 1D
FB 98 04 08 75 50 33 05 14 99 04 08 3A 05 FC 98
04 08 75 42 32 15 15 99 04 08 3A 15 FD 98 04 08
75 34 32 0D 16 99 04 08 3A 0D FE 98 04 08 75 26
89 FB 32 1D 17 99 04 08 3A 1D FF 98 04 08 75 16
C7 04 24 0E 87 04 08 E8 14 FE FF FF 8D 65 F4 31
C0 5B 5E 5F 5D C3 C7 04 24 1C 87 04 08 E8 FE FD
FF FF EB E8 31 ED 5E 89 E1 83 E4 F0 50 54 52 68
60 86 04 08 68 70 86 04 08 51 56 68 B0 83 04 08
E8 FB FD FF FF F4 90 90 90 90 90 90 90 90 90 90
B8 07 99 04 08 2D 04 99 04 08 83 F8 06 77 02 F3
C3 B8 00 00 00 00 85 C0 74 F5 55 89 E5 83 EC 18
C7 04 24 04 99 04 08 FF D0 C9 C3 90 8D 74 26 00
B8 04 99 04 08 2D 04 99 04 08 C1 F8 02 89 C2 C1
EA 1F 01 D0 D1 F8 75 02 F3 C3 BA 00 00 00 00 85
D2 74 F5 55 89 E5 83 EC 18 89 44 24 04 C7 04 24
04 99 04 08 FF D2 C9 C3 90 8D B4 26 00 00 00 00
80 3D 04 99 04 08 00 75 13 55 89 E5 83 EC 08 E8
7C FF FF FF C6 05 04 99 04 08 01 C9 F3 C3 66 90
A1 D0 97 04 08 85 C0 74 1E B8 00 00 00 00 85 C0
74 15 55 89 E5 83 EC 18 C7 04 24 D0 97 04 08 FF
D0 C9 E9 79 FF FF FF E9 74 FF FF FF 90 90 90 90
55 89 E5 5D C3 8D 74 26 00 8D BC 27 00 00 00 00
55 89 E5 57 56 53 E8 4F 00 00 00 81 C3 4D 12 00
00 83 EC 1C E8 9B FC FF FF 8D BB 04 FF FF FF 8D
83 00 FF FF FF 29 C7 C1 FF 02 85 FF 74 24 31 F6
8B 45 10 89 44 24 08 8B 45 0C 89 44 24 04 8B 45
08 89 04 24 FF 94 B3 00 FF FF FF 83 C6 01 39 FE
72 DE 83 C4 1C 5B 5E 5F 5D C3 8B 1C 24 C3 90 90
55 89 E5 53 83 EC 04 E8 00 00 00 00 5B 81 C3 EC
11 00 00 59 5B C9 C3 00 03 00 00 00 01 00 02 00
25 73 0A 50 6C 65 61 73 65 20 69 6E 70 75 74 20
79 6F 75 72 20 66 6C 61 67 3A 00 25 73 00 59 6F
75 20 61 72 65 20 72 69 67 68 74 00 59 6F 75 20
61 72 65 20 77 72 6F 6E 67 00'''.replace(' ',' ').replace('\n','')
b=a.split(' ')
print hex(len(b))
c=0x37a
for i in b:
e=c>>27
d=c&0x80000000
if(d==0x80000000):
e|=0xffffffe0
c=int(i,16)^e^32*c
c&= 0xffffffff
print hex(c)

REVERSE-Daily(4)-Elfcrackme2的更多相关文章

  1. HNU 13411 Reverse a Road II(最大流+BFS)经典

    Reverse a Road II Time Limit: 10000ms, Special Time Limit:25000ms, Memory Limit:65536KB Total submit ...

  2. LeetCode 7. Reverse Integer

    Reverse digits of an integer. Example1: x = 123, return 321 Example2: x = -123, return -321 Have you ...

  3. 【uwp】浅谈China Daily 中划词翻译的实现

    学习uwp开发也有一段时间了,最近上架了一个小应用(China Daily),现在准备将开发中所学到的一些东西拿出来跟大家分享交流一下. 先给出应用的下载链接:China Daily , 感兴趣的童鞋 ...

  4. js sort() reverse()

    数组中存在的两个方法:sort()和reverse() 直接用sort(),如下: ,,,,,,,,,,,]; console.log(array.sort());ps:[0, 1, 2, 2, 29 ...

  5. [LeetCode] Reverse Vowels of a String 翻转字符串中的元音字母

    Write a function that takes a string as input and reverse only the vowels of a string. Example 1:Giv ...

  6. [LeetCode] Reverse String 翻转字符串

    Write a function that takes a string as input and returns the string reversed. Example: Given s = &q ...

  7. [LeetCode] Reverse Linked List 倒置链表

    Reverse a singly linked list. click to show more hints. Hint: A linked list can be reversed either i ...

  8. [LeetCode] Reverse Bits 翻转位

    Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represented in ...

  9. [LeetCode] Reverse Words in a String II 翻转字符串中的单词之二

    Given an input string, reverse the string word by word. A word is defined as a sequence of non-space ...

  10. [LeetCode] Reverse Words in a String 翻转字符串中的单词

    Given an input string, reverse the string word by word. For example, Given s = "the sky is blue ...

随机推荐

  1. win32 Dll 中添加afx.h 出现如下错误 error LNK2005: _DllMain@12 already defined

    win32 Dll 中添加afx.h 出现如下错误 nafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in ...

  2. 工作需求----表单select多选交互

    由于工作需求接触select框多选的情况,以下是我分享的代码,主要是进入页面默认选中.支持多选属性: 1.html内容 multiple=”multiple” 属性为多选属性 <div clas ...

  3. CSS实现各种形状

    CSS3的一个非常酷的特性是允许我们创建各种规则和不规则形状的图形,从而可以减少图片的使用.以前只能在Photoshop等图像编辑软件中制作的复杂图形现在使用CSS3就可以完成了.通过使用新的CSS属 ...

  4. cacti结合nagios

    使用系统ubuntu12.0.45 监控软件,cacti 使用的是源码安装系统自带的版本过低需要添加插件 nagios采用的系统自带版本 安装nagios apt-get install nagios ...

  5. cacti监控juniper路由器

    之前也没有写过博客,但是最近一直在做监控.从网上查找很多资料都还是感觉差一点.所以自己添加一份我在cacti监控路由器的步骤. 环境,ubuntu14.04,apt-get install cacti ...

  6. iOS生成静态库方法

    在iOS的开发过程中,我们常常用到第三方的库.比如支付.地图.广告等. 那么,如何制作自己的库文件呢? 如何将自己写的功能类编译成库文件,分发给其他人来使用呢并做成通用库里? iOS开发一年多来没有制 ...

  7. 极光推送Jpush(v3)服务端PHP版本集成(V3版本只调用推送API)

    因为版本升级,极光推送的API也有了V3,功能也更丰富了,但是对于我们有的用户来说,我们还是只需要调用推送的API就够了. 下载了一份PHP服务端的SDK(下载地址:http://docs.jpush ...

  8. 2014 NOIP 赛前自我整理提醒。

    空谈WA,实干AC. 所以作为一个就要上战场的OIer ,实干当然是最重要,但刷题不在多,要点牢记是关键,虽然本渣没记住多少,但还是列几点值得注意的小点. 1.战场上容不得失误. 对于每日都要敲键盘的 ...

  9. python网络编程【二】(使用UDP)

    UDP通信几乎不使用文件对象,因为他们往往不能为数据如何发送和接受提供足够的控制.下面是一个基本的UPD客户端: #!/usr/bin/env python import socket,sys hos ...

  10. C++学习进度0

    昨天,又把<C++ primer> 刷了一遍,这一次看的是陈硕大大的评注版,重点看了陈硕的注释,<Accelerated C++>去年就把代码巧了一遍,<C++ prim ...