盒子
盒子
文章目录
  1. 探测指令集架构
  2. GetPc
    1. x86
    2. x64
  3. 上次调用返回地址
    1. 32位
    2. 64位
  4. int3断点
  5. 跑题的吐槽

Shellcode/Environment

源自:blackhat.life/Shellcode/Environment,意译,原文是用gas的,我比较喜欢nasm语法。。。。。。

一般汇编文件开头这样写入口:

global _start
_start:

然后,比如64位,

nasm -f elf64 get_pc_64.s

最后链接:

ld get_pc_64.o -o get_pc_64

可以用gdb来载入查看

 ~/Work/project/blackhat/shellcode  gdb -q a.out
Reading symbols from /home/reverland/Work/project/blackhat/shellcode/a.out...(no debugging symbols found)...done.
(gdb) disassemble _start,+10
Dump of assembler code from 0x4000b0 to 0x4000ba:
   0x00000000004000b0 <_start+0>:       jmp    0x4000b3 <startup>
   0x00000000004000b2 <pc+0>:   nop
   0x00000000004000b3 <startup+0>:      lea    rax,[rip+0xfffffffffffffff8]        # 0x4000b2 <pc>
End of assembler dump.

不过只是为了看汇编效果的话,不用链接直接看就是

~ objdump -d -M intel last_call_32.o
last_call_32.o:     file format elf32-i386

Disassembly of section .text:

00000000 <_start>:
   0:   8b 44 24 fc             mov    eax,DWORD PTR [esp-0x4]

另外ndisasmrasm2用不顺手,怎么和我想得到的结果不一样= =

好了,废话完了,正文。


shellcode能在当前环境下,探测指令集架构,程序指针,上一个返回的地址,或者绕过和探测int3断点。

探测指令集架构

Architecture Spanning Shellcode

GetPc

GetPc是用来获得当前指令指针的技术。如果写自修改shellcode这个挺游泳,或者对那些必须知道自己所处环境的shellcode,因为环境信息在代码执行前不可预知。

x86

call会把下一行地址压栈

jmp startup
getpc:
   mov eax [esp]
   ret
startup:
call getpc       ; the %eax register now contains %eip on the next line

x64

同理

jmp startup
getpc:
   mov rax, [rsp]
   ret
startup:
call getpc       ; the %rax register now contains %rip on the next line 

或者x64可以直接操作rip

jmp startup
pc:
  nop
startup:
  lea rax, [rel pc]  ; the %rax register now contains the address of `pc'.

上次调用返回地址

一般情况下,在缓冲区溢出攻击中执行shellcode,假设nop sled没有改变堆栈,函数的返回地址是[rsp-0x8]或者[esp-0x4],就是在溢出过程中覆盖的掉那个堆栈返回的地址。很多情况下,这能在写多态shellcode时替代GetPc. alphanumeric last call在64位系统中有13字节。

32位

Null-free的shellcode(没有\x00)

mov eax, [esp-0x4]

64位

Null-free

mov [rax], [rsp-0x8]

int3断点

int3断点可以被探测出来。

global _start
_start:
jmp startup

go_retro:
pop rcx
inc rcx
jmp [rcx]

startup:
call go_retro

volatile_segment:
push 0x3458686a
push 0x0975c084
nop

关键的代码在

push 0x3458686a
push 0x0975c084

这是啥呢?

 ~/Work/project/blackhat/shellcode  rasm2 -d "6a6858346885c07509"
push 0x68
pop eax
xor al, 0x68
test eax, eax
jne 0x12

当在第二个push加断点时,会把上一个字节暂改为\xcc

000000000000000d <volatile_segment>:
   d:   68 6a 68 58 cc          push   0xcc58686a
  12:   68 84 c0 75 09          push   0x975c084
  17:   90                      nop

这时,推到栈上的就是:

 ~/Work/project/blackhat/shellcode  rasm2 -d "6a685834cc85c07509"
push 0x68
pop eax
xor al, 0xffffffcc
test eax, eax
jne 0x12

这样就会向前跳0x12而不是激发断点。

我们可以试试,下次再写loader,所以。。。

 ~/Work/project/blackhat/shellcode  gdb -q detect_breakpoint
Reading symbols from /home/lyy/Work/project/blackhat/shellcode/detect_breakpoint...(no debugging symbols found)...done.
(gdb) disassemble _start,+20
Dump of assembler code from 0x4000b0 to 0x4000c4:
   0x00000000004000b0 <_start+0>:       jmp    0x4000b8 <startup>
   0x00000000004000b2 <go_retro+0>:     pop    rcx
   0x00000000004000b3 <go_retro+1>:     inc    rcx
   0x00000000004000b6 <go_retro+4>:     jmp    QWORD PTR [rcx]
   0x00000000004000b8 <startup+0>:      call   0x4000b2 <go_retro>
   0x00000000004000bd <volatile_segment+0>:     push   0x3458686a
   0x00000000004000c2 <volatile_segment+5>:     push   0x975c084
End of assembler dump.
(gdb) b *0x00000000004000c2
Breakpoint 1 at 0x4000c2
(gdb) r
Starting program: /home/lyy/Work/project/blackhat/shellcode/detect_breakpoint 
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffd000

Program received signal SIGSEGV, Segmentation fault.
0x00000000004000b6 in go_retro ()
(gdb) 

没有碰到断点!!(那啥sigsegv了,看样子shellcode loader应该先写。。。)

ps: 这让我想起来之前反gdb调试的一些学习,下次再写吧

跑题的吐槽

作为一个什么都会点什么都不会的渣,也被推到投简历找实习的浪潮之中,立马被北邮的互联网求职氛围吓尿了,看到bswgd在《谈谈在校程序员技能培养》中谈到:

几乎是从事互联网行业的人都知道,北邮人找互联网的工作特别拿手。 甚至被说成如蝗虫过境一般。事实却是也是如此。

往身边看看,真是这感觉。。。

看了依云仙子的《再三错过》中心理好难过,阴影一直如影随形。

于是在大家都投完简历我还是拖延着什么也没写,只是把仙子当年的感慨找来看了看。

至于我自己,还是趁着没毕业多调查下吧