xorddos 样本进程隐藏的小伎俩

进程隐藏

上周由于工作原因接触到xorddos的样本,这个样本在过去一年的时间里非常常见,
变种也很多,拿到的样本比较有趣的是 ps 无法发现进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@localhost ~]# ps -ef  | grep /usr/bin

...

root 4597 4594 0 00:37 ? 00:00:00 gnome-pty-helper
root 4598 4594 0 00:37 pts/1 00:00:00 bash
oracle 5359 1 0 00:41 ? 00:00:00 ora_smco_orcl
oracle 5378 1 0 00:41 ? 00:00:00 ora_w000_orcl
oracle 5586 1 0 00:42 ? 00:00:00 ora_j000_orcl
oracle 5588 1 0 00:42 ? 00:00:00 ora_j001_orcl
root 5666 1 0 00:43 ? 00:00:00 sh
root 5669 1 0 00:43 ? 00:00:00 echo "find"
root 5672 1 0 00:43 ? 00:00:00 ls -la
root 5675 1 0 00:43 ? 00:00:00 bash
root 5678 1 0 00:43 ? 00:00:00 gnome-terminal
root 5683 1 0 00:43 ? 00:00:00 cd /etc
root 5686 1 0 00:43 ? 00:00:00 top
root 5689 1 0 00:43 ? 00:00:00 sh
root 5692 1 0 00:43 ? 00:00:00 gnome-terminal
root 5695 1 0 00:43 ? 00:00:00 ifconfig
root 5696 4598 0 00:43 pts/1 00:00:00 ps -ef

而使用lsof却可以清除地看见样本正在努力地干活。

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
[root@localhost ~]# lsof +d /usr/bin
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
hidd 1853 root txt REG 3,1 33708 2467454 /usr/bin/hidd
ckucbzknt 2014 root txt REG 3,1 610331 2459176 /usr/bin/ckucbzkntb
xfs 2143 xfs txt REG 3,1 107460 2468483 /usr/bin/xfs
Xorg 3117 root txt REG 3,1 1890596 2466732 /usr/bin/Xorg
gnome-ses 4073 root txt REG 3,1 129356 2459482 /usr/bin/gnome-session
ssh-agent 4201 root txt REG 3,1 88996 2467513 /usr/bin/ssh-agent
dbus-laun 4245 root txt REG 3,1 23796 2471600 /usr/bin/dbus-launch
gnome-key 4255 root txt REG 3,1 97396 2473617 /usr/bin/gnome-keyring-daemon
metacity 4290 root txt REG 3,1 521080 2464500 /usr/bin/metacity
gnome-pan 4296 root txt REG 3,1 540868 2465177 /usr/bin/gnome-panel
nautilus 4298 root txt REG 3,1 1348932 2461620 /usr/bin/nautilus
gnome-vol 4310 root txt REG 3,1 65240 2464498 /usr/bin/gnome-volume-manager
bt-applet 4334 root txt REG 3,1 30452 2464773 /usr/bin/bt-applet
nm-applet 4352 root txt REG 3,1 312432 2467723 /usr/bin/nm-applet
gnome-pow 4381 root txt REG 3,1 195284 2459473 /usr/bin/gnome-power-manager
pam-panel 4383 root txt REG 3,1 39148 2461862 /usr/bin/pam-panel-icon
dbus-laun 4473 root txt REG 3,1 23796 2471600 /usr/bin/dbus-launch
gnome-scr 4512 root txt REG 3,1 168628 2468487 /usr/bin/gnome-screensaver
gnome-ter 4594 root txt REG 3,1 309368 2464648 /usr/bin/gnome-terminal
gadcgkcqn 4681 root txt REG 3,1 610331 2460159 /usr/bin/gadcgkcqni
gadcgkcqn 4684 root txt REG 3,1 610331 2460159 /usr/bin/gadcgkcqni
gadcgkcqn 4687 root txt REG 3,1 610331 2460159 /usr/bin/gadcgkcqni
gadcgkcqn 4690 root txt REG 3,1 610331 2460159 /usr/bin/gadcgkcqni
gadcgkcqn 4693 root txt REG 3,1 610331 2460159 /usr/bin/gadcgkcqni

阅读汇编代码,分析具体原因,发现xorddos将一些关键信息加密了,F5处理过的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl encrypt_code(int a1, int a2)
{
signed int v2; // ecx@2

if ( a2 > 0 )
{
v2 = 0;
do
{
*(_BYTE *)(v2 + a1) ^= xorkeys[(((_BYTE)v2 + ((unsigned int)(v2 >> 31) >> 28)) & 0xF)
- ((unsigned int)(v2 >> 31) >> 28)];
++v2;
}
while ( v2 != a2 );
}
return a1;
}

xorkey 为 BB2FA36AAA9541F0

用idapython 写个小脚本,简单处理一下。

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
from idautils import *
from idc import *


def get_string(addr):
out = ""
while True:
if Byte(addr) != 0:
out += chr(Byte(addr))
else:
break
addr += 1
return out

def decrypt(data):

xorkey = 'BB2FA36AAA9541F0'
length = len(data)
o = ""
if length > 0:
v2 = 0
while v2 < length:
o += chr( ord(data[v2]) ^ ord(xorkey[((v2 + ((v2 >> 31) >> 28)) & 0xF) - ( (v2 >> 31) >> 28)]) )
v2 += 1

return o

ea = ScreenEA()
string = get_string(ea)
dec = decrypt(string)
print 'Addr: 0x%x, %s' % (ea, dec)
MakeComm(ea, dec)

处理后可以看到伪装的命令行信息,daemonname。

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
.data:080CBB40 daemonname      db '!#Ff3VE.-7',17h,'V[_ 0',0 ; DATA XREF: main+31Eo
.data:080CBB40 ; main+4AEo ...
.data:080CBB40 ; cat resolv.conf
.data:080CBB51 align 4
.data:080CBB54 a12 db '1*2',0 ; sh
.data:080CBB58 db 0
.data:080CBB59 db 0
.data:080CBB5A db 0
.data:080CBB5B db 0
.data:080CBB5C db 0
.data:080CBB5D db 0
.data:080CBB5E db 0
.data:080CBB5F db 0
.data:080CBB60 db 0
.data:080CBB61 db 0
.data:080CBB62 db 0
.data:080CBB63 db 0
.data:080CBB64 db 0
.data:080CBB65 db 0
.data:080CBB66 db 0
.data:080CBB67 db 0
.data:080CBB68 db 20h ; bash
.data:080CBB69 db 23h ; #
.data:080CBB6A db 41h ; A
.data:080CBB6B db 2Eh ; .
.data:080CBB6C db 41h ; A
.data:080CBB6D db 0
.data:080CBB6E db 0
.data:080CBB6F db 0
.data:080CBB70 db 0
.data:080CBB71 db 0

...

.data:080CBBB8 db 2Eh ; . ; ls -la
.data:080CBBB9 db 31h ; 1
.data:080CBBBA db 12h
.data:080CBBBB db 6Bh ; k
.data:080CBBBC db 2Dh ; -
.data:080CBBBD db 52h ; R
.data:080CBBBE db 36h ; 6
.data:080CBBBF db 0
.data:080CBBC0 db 0
.data:080CBBC1 db 0
.data:080CBBC2 db 0
.data:080CBBC3 db 0
.data:080CBBC4 db 0
.data:080CBBC5 db 0
.data:080CBBC6 db 0
.data:080CBBC7 db 0
.data:080CBBC8 db 0
.data:080CBBC9 db 0
.data:080CBBCA db 0
.data:080CBBCB db 0
.data:080CBBCC db 36h ; 6 ; top
.data:080CBBCD db 2Dh ; -
.data:080CBBCE db 42h ; B
.data:080CBBCF db 46h ; F
.data:080CBBD0 db 0
.data:080CBBD1 db 0
.data:080CBBD2 db 0

...

呵呵,已经看到 top, ls -al 等信息了,查看daemonname 的交叉引用,发现在main函数
中,到main里看看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.text:0804AC30 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0804AC30 public main
.text:0804AC30 main proc near ; DATA XREF: _start+17o

....

.text:0804AF4E mov ebx, offset daemonname ; "!#Ff3VE.-7\x17V[_ 0"

...

.text:0804AFC2 loc_804AFC2: ; CODE XREF: main+3ABj
.text:0804AFC2 mov [esp], ebx
.text:0804AFC5 add ebx, 14h
.text:0804AFC8 mov dword ptr [esp+4], 14h
.text:0804AFD0 call encrypt_code
.text:0804AFD5 cmp ebx, offset unk_80CBD0C
.text:0804AFDB jnz short loc_804AFC2

这段汇编代码,使用了一个循环,调用encrypt_code 对daemonname进行了解密。
后面的代码,用到了daemonname的地方有下面几处,

第一处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.text:0804B29F                 call    getpid
.text:0804B2A4 mov dword ptr [esp+8], (offset aDD+3) ; "%d"
.text:0804B2AC mov dword ptr [esp+4], 0Ah
.text:0804B2B4 mov [esp], esi ;第三形参 pid
.text:0804B2B7 mov [esp+0Ch], eax
.text:0804B2BB call snprintf
.text:0804B2C0 mov dword ptr [esp+4], 17h
.text:0804B2C8 mov dword ptr [esp], 0
.text:0804B2CF call randomid
.text:0804B2D4 mov [esp+8], esi
.text:0804B2D8 mov [esp], edi ;第一形参 要跑的木马
.text:0804B2DB movzx eax, ax
.text:0804B2DE lea eax, [eax+eax*4]
.text:0804B2E1 lea eax, daemonname[eax*4] ; "!#Ff3VE.-7\x17V[_ 0"
.text:0804B2E8 mov [esp+4], eax ; 第二形参 daemonname
.text:0804B2EC call LinuxExec_Argv2

第二处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:0804B932                 lea     edx, [ebp+var_1888]
.text:0804B938 add ebx, 1
.text:0804B93B mov [esp], edx
.text:0804B93E call randmd5
.text:0804B943 mov [ebp+var_22], 0
.text:0804B94A mov [ebp+var_1E], 0
.text:0804B951 mov [ebp+var_1A], 0
.text:0804B957 call getpid
.text:0804B95C mov dword ptr [esp+8], (offset aDD+3) ; "%d"
.text:0804B964 mov dword ptr [esp+4], 0Ah
.text:0804B96C mov [esp], esi
.text:0804B96F mov [esp+0Ch], eax
.text:0804B973 call snprintf
.text:0804B978 mov dword ptr [esp+4], 17h
.text:0804B980 mov dword ptr [esp], 0
.text:0804B987 call randomid
.text:0804B98C mov [esp+8], esi
.text:0804B990 movzx eax, ax
.text:0804B993 lea eax, [eax+eax*4]
.text:0804B996 lea eax, daemonname[eax*4] ; "!#Ff3VE.-7\x17V[_ 0"
.text:0804B99D mov [esp+4], eax
.text:0804B9A1 lea eax, [ebp+var_1888]
.text:0804B9A7 mov [esp], eax
.text:0804B9AA call LinuxExec_Argv2

第三处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:0804B9DF                 lea     edx, [ebp+var_1C88]
.text:0804B9E5 add ebx, 1
.text:0804B9E8 mov [esp], edx
.text:0804B9EB call randmd5
.text:0804B9F0 mov [ebp+var_22], 0
.text:0804B9F7 mov [ebp+var_1E], 0
.text:0804B9FE mov [ebp+var_1A], 0
.text:0804BA04 call getpid
.text:0804BA09 mov dword ptr [esp+8], (offset aDD+3) ; "%d"
.text:0804BA11 mov dword ptr [esp+4], 0Ah
.text:0804BA19 mov [esp], esi
.text:0804BA1C mov [esp+0Ch], eax
.text:0804BA20 call snprintf
.text:0804BA25 mov dword ptr [esp+4], 17h
.text:0804BA2D mov dword ptr [esp], 0
.text:0804BA34 call randomid
.text:0804BA39 mov [esp+8], esi
.text:0804BA3D movzx eax, ax
.text:0804BA40 lea eax, [eax+eax*4]
.text:0804BA43 lea eax, daemonname[eax*4] ; "!#Ff3VE.-7\x17V[_ 0"
.text:0804BA4A mov [esp+4], eax
.text:0804BA4E lea eax, [ebp+var_1C88]
.text:0804BA54 mov [esp], eax
.text:0804BA57 call LinuxExec_Argv2

都是作为LinuxExec_Argv2 参数使用的,接着来看LinuxExec_Argv2 的代码

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
.text:08048520 LinuxExec_Argv2 proc near               ; CODE XREF: DelService+B3p
.text:08048520 ; DelService+CBlp ...
.text:08048520
.text:08048520 argv = dword ptr -18h
.text:08048520 var_14 = dword ptr -14h
.text:08048520 var_10 = dword ptr -10h
.text:08048520 var_C = dword ptr -0Ch
.text:08048520 var_8 = dword ptr -8
.text:08048520 var_4 = dword ptr -4
.text:08048520 file = dword ptr 8
.text:08048520 arg_4 = dword ptr 0Ch
.text:08048520 arg_8 = dword ptr 10h
.text:08048520
.text:08048520 push ebp
.text:08048521 mov ebp, esp
.text:08048523 sub esp, 28h
.text:08048526 mov [ebp+var_4], esi
.text:08048529 mov esi, [ebp+file]
.text:0804852C mov [ebp+var_8], ebx
.text:0804852F mov [ebp+argv], 0
.text:08048536 mov [ebp+var_14], 0
.text:0804853D mov [ebp+var_10], 0
.text:08048544 mov [ebp+var_C], 0
.text:0804854B call doublefork
.text:08048550 test eax, eax
.text:08048552 jz short ZERO
.text:08048554 mov ebx, [ebp+var_8]
.text:08048557 mov esi, [ebp+var_4]
.text:0804855A mov esp, ebp
.text:0804855C pop ebp
.text:0804855D retn
.text:0804855E ; ---------------------------------------------------------------------------
.text:0804855E
.text:0804855E ZERO: ; CODE XREF: LinuxExec_Argv2+32j
.text:0804855E mov ebx, 3
.text:08048563
.text:08048563 LOOP: ; CODE XREF: LinuxExec_Argv2+54j
.text:08048563 mov [esp], ebx ; fd
.text:08048566 add ebx, 1
.text:08048569 call close
.text:0804856E cmp ebx, 400h ;400h == 1024
.text:08048574 jnz short LOOP
.text:08048576 mov eax, [ebp+arg_4]
.text:08048579 mov [ebp+argv], esi
.text:0804857C mov [esp], esi ; file
.text:0804857F mov [ebp+var_14], eax
.text:08048582 mov eax, [ebp+arg_8];eax = pid
.text:08048585 mov [ebp+var_10], eax
.text:08048588 lea eax, [ebp+argv]
.text:0804858B mov [esp+4], eax ; argv
.text:0804858F call execvp
.text:08048594 mov dword ptr [esp], 0 ; status
.text:0804859B call exit
.text:0804859B LinuxExec_Argv2 endp

LinuxExec_Argv2 有三个参数。最终执行了execvp

1
2
3
4
.text:0804857C                 mov     [esp], esi      ; file 
...
.text:0804858B mov [esp+4], eax ; argv
.text:0804858F call execvp

伪代码为,

1
execvp(file, &argv);

file 就是arg_0, 需要分析argv, 调出栈图就比较清晰了。

1
2
3
4
5
6
7
8
9
10
11
12
-00000018 argv            dd ?                    ; offset
-00000014 var_14 dd ?
-00000010 var_10 dd ?
-0000000C var_C dd ?
-00000008 var_8 dd ?
-00000004 var_4 dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)
+00000008 file dd ? ; offset
+0000000C arg_4 dd ?
+00000010 arg_8 dd ?

首先是这句

1
2
3
4
5
6
.text:08048529                 mov     esi, [ebp+file]
...
.text:0804852F mov [ebp+argv], 0
...
.text:08048579 mov [ebp+argv], esi

执行了这几句代码后,栈图发生了变化

1
2
3
4
5
6
7
8
9
10
11
-00000018 argv            arg_0                       ; offset
-00000014 var_14 dd ?
-00000010 var_10 dd ?
-0000000C var_C dd ?
-00000008 var_8 dd ?
-00000004 var_4 dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)
+00000008 file dd ? ; offset
+0000000C arg_4 dd ?
+00000010 arg_8 dd ?

再看这几句代码

1
2
3
4
.text:08048576                 mov     eax, [ebp+arg_4]
.text:08048579 mov [ebp+argv], esi
...
.text:0804857F mov [ebp+var_14], eax

执行了这几句代码后,栈图发生了变化

1
2
3
4
5
6
7
8
9
10
11
-00000018 argv            arg_0                   ; offset
-00000014 var_14 arg_4
-00000010 var_10 dd ?
-0000000C var_C dd ?
-00000008 var_8 dd ?
-00000004 var_4 dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)
+00000008 file dd ? ; offset
+0000000C arg_4 dd ?
+00000010 arg_8 dd ?

接下来是这几句代码

1
2
.text:08048582                 mov     eax, [ebp+arg_8];eax = pid
.text:08048585 mov [ebp+var_10], eax

执行了这几句代码后,栈图发生了变化

1
2
3
4
5
6
7
8
9
10
11
12
-00000018 argv            arg_0                   ; offset
-00000014 var_14 arg_4
-00000010 var_10 arg_8
-0000000C var_C 0
-00000008 var_8 dd ?
-00000004 var_4 dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)
+00000008 file dd ? ; offset
+0000000C arg_4 dd ?
+00000010 arg_8 dd ?
`

main函数中对LinuxExec_Argv2 的调用的为代码为

1
LinuxExec_Argv2('木马路径', '伪装命令行', pid);

因此最后调用的execvp的伪代码为

1
execvp('木马路径', argv);

将进入 main 函数参数个数为3的流程,用IDA重命名后,关键代码为

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
text:0804B5D3 PARAM_NUM_3:                            ; CODE XREF: main+3CDj

.text:0804B5D3 lea eax, [ebp+var_18]
.text:0804B5D6 mov [esp+4], eax
.text:0804B5DA lea eax, [ebp+self_path]
.text:0804B5E0 mov [esp], eax
.text:0804B5E3 call readfile
.text:0804B5E8 mov edx, [ebp+argv_arr]
.text:0804B5EE mov ebx, [edx+4]
.text:0804B5F1 mov [ebp+self_file_content], eax
.text:0804B5F7 mov [esp], ebx
.text:0804B5FA call strlen
.text:0804B5FF mov [esp+4], ebx
.text:0804B603 mov [esp+8], eax
.text:0804B607 lea eax, [ebp+fake_cmd]
.text:0804B60D mov [esp], eax
.text:0804B610 call memmove
.text:0804B615 mov dword ptr [esp+0Ch], 0
.text:0804B61D mov dword ptr [esp+8], 0Ah
.text:0804B625 mov dword ptr [esp+4], 0
.text:0804B62D mov edx, [ebp+argv_arr]
.text:0804B633 mov eax, [edx+8]
.text:0804B636 mov [esp], eax
.text:0804B639 call __strtol_internal
.text:0804B63E mov esi, eax
.text:0804B640 mov eax, [ebp+argv_arr]
.text:0804B646 mov ebx, [eax]
.text:0804B648 mov [esp], ebx
.text:0804B64B call strlen
.text:0804B650 mov [esp], ebx
.text:0804B653 mov dword ptr [esp+4], 0
.text:0804B65B mov [esp+8], eax
.text:0804B65F call memset
.text:0804B664 mov edx, [ebp+argv_arr]
.text:0804B66A mov ebx, [edx+4]
.text:0804B66D mov [esp], ebx
.text:0804B670 call strlen
.text:0804B675 mov [esp], ebx
.text:0804B678 mov dword ptr [esp+4], 0
.text:0804B680 mov [esp+8], eax
.text:0804B684 call memset
.text:0804B689 mov eax, [ebp+argv_arr]
.text:0804B68F mov ebx, [eax+8]
.text:0804B692 mov [esp], ebx
.text:0804B695 call strlen
.text:0804B69A mov [esp], ebx
.text:0804B69D mov dword ptr [esp+4], 0
.text:0804B6A5 mov [esp+8], eax
.text:0804B6A9 call memset
.text:0804B6AE lea edx, [ebp+fake_cmd]
.text:0804B6B4 mov [esp+4], edx
.text:0804B6B8 mov edx, [ebp+argv_arr]
.text:0804B6BE mov eax, [edx]
.text:0804B6C0 mov [esp], eax
.text:0804B6C3 call strcpy
.text:0804B6C8 lea eax, [ebp+filename]
.text:0804B6CE mov [esp+0Ch], esi
.text:0804B6D2 lea esi, [ebp+randstr_10]

上面代码的原理大致等同于下面这段代码

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
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv){
char fake_cmd[256];
memset(&fake_cmd, 0, 256);
char * argv_arr_1 = argv[1];
int argv_arr_1_length = strlen(argv[1]);
memmove(&fake_cmd, argv_arr_1, argv_arr_1_length);
long pid_long = strtol(argv[2], 0, 10);
char * v29 = (char *)*argv;
int v30 = strlen(*argv);
memset(v29, 0, v30);
char * v31 = argv[1];
int v32 = strlen(argv[1]);
memset(v31, 0, v32);
char * v33 = argv[2];
int v34 = strlen(argv[2]);
memset(v33, 0, v34);
strcpy(*argv, fake_cmd);
sleep(300);
}

编译后执行可以看到效果和运行样本的一样。

1
2
3
4
5
6
7
8
9
10
11
➜  ~ gcc -o fakeexe exe.c
➜ ~ ./fakeexe "ls -al" 2554

➜ ~ cat /proc/2605/cmdline
ls -al

➜ ~ ls -l /proc/2605/exe
lrwxrwxrwx. 1 henices henices 0 8月 2 12:01 /proc/2605/exe -> /home/henices/research/xorddos/fakeexe

➜ ~ ps -elf | grep "ls -al" | grep -v grep
0 S henices 2605 25307 0 80 0 - 1043 hrtime 12:01 pts/5 00:00:00 ls -al

其实效果并不好,可以轻易发现踪迹。

1
2
3
➜  ~ ps -e | grep fakeexe
2605 pts/9 00:00:00 fakeexe

其实有更好的做法,使用 prctl ,至少可以把ps给搞定。

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
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>

int main(int argc, char **argv){
char fake_cmd[256];
memset(&fake_cmd, 0, 256);
char * argv_arr_1 = argv[1];
int argv_arr_1_length = strlen(argv[1]);
memmove(&fake_cmd, argv_arr_1, argv_arr_1_length);
long pid_long = strtol(argv[2], 0, 10);
char * v29 = (char *)*argv;
int v30 = strlen(*argv);
memset(v29, 0, v30);
char * v31 = argv[1];
int v32 = strlen(argv[1]);
memset(v31, 0, v32);
char * v33 = argv[2];
int v34 = strlen(argv[2]);
memset(v33, 0, v34);
strcpy(*argv, fake_cmd);
prctl(PR_SET_NAME, "bash");
sleep(300);
}

编译执行后可以看到效果。

1
2
3
4
5
6
7
8
➜  ~ ps -e | grep bash
4858 pts/5 00:00:00 bash

➜ ~ cat /proc/4858/cmdline
ls -al

➜ ~ lsof -d txt | grep fakeexe
bash 4858 henices txt REG 253,2 8816 4588423 /home/henices/research/xorddos/fakeexe

xorddos 的多态 (Polymorphic)

xorddos这个样本还值得一提的是,这个样本会不断变化,多态这个词翻译的可能不太准确,
可以参见上面的英文,自行理解。

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
int __cdecl randmd5(char *filename)
{
int fd; // eax@1
int fd_dup; // esi@1
mode_t v4; // [sp+8h] [bp-20h]@0
int addr; // [sp+15h] [bp-13h]@1
int v6; // [sp+19h] [bp-Fh]@1
__int16 v7; // [sp+1Dh] [bp-Bh]@1
char v8; // [sp+1Fh] [bp-9h]@1

addr = 0;
v6 = 0;
v7 = 0;
v8 = 0;
fd = open(filename, 1, v4);
fd_dup = fd;
if ( fd > 0 )
{
lseek(fd, 0, SEEK_END);
randstr((int)&addr, 10);
write(fd_dup, &addr, 11u);
close(fd_dup);
}
return 0;
}

xorddos 样本多态主要就是用这个函数,每次在文件末尾写上10个字节的随机字符。
这样样本md5和大小都会发生变化,使得一些检测方法失效。

其他

正因为这种隐藏方法并不理想,后面xorddos出现了带rootkit的版本,进化了。


xorddos 样本进程隐藏的小伎俩
https://usmacd.com/cn/xorddos_hide/
作者
henices
发布于
2023年9月6日
许可协议