目前已经成功将100扇区的512bytes内容拷贝到物理地址0x10000上,详见下面memory dump:
磁盘上hex:
memory dump:
<bochs:18> xp /512bx 0x10000
[bochs]:
0x0000000000010000 <bogus+ 0>: 0xbe 0x01 0x00 0x00 0x00 0x00 0x10 0x00
0x0000000000010008 <bogus+ 8>: 0x00 0x00 0x01 0x00 0x10 0x00 0x00 0x00
0x0000000000010010 <bogus+ 16>: 0xb8 0x12 0x00 0x89 0xc5 0xb9 0x10 0x00
0x0000000000010018 <bogus+ 24>: 0xb8 0x01 0x13 0xbb 0x0c 0x00 0xb2 0x00
0x0000000000010020 <bogus+ 32>: 0xcd 0x10 0x62 0x79 0x65 0x62 0x79 0x65
0x0000000000010028 <bogus+ 40>: 0x20 0x6c 0x6f 0x61 0x64 0x65 0x72 0x2c
0x0000000000010030 <bogus+ 48>: 0x20 0x68 0x65 0x72 0x65 0x27 0x73 0x20
0x0000000000010038 <bogus+ 56>: 0x63 0x6c 0x69 0x65 0x6e 0x74 0x51 0x51
0x0000000000010040 <bogus+ 64>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010048 <bogus+ 72>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010050 <bogus+ 80>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010058 <bogus+ 88>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010060 <bogus+ 96>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010068 <bogus+ 104>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010070 <bogus+ 112>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010078 <bogus+ 120>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010080 <bogus+ 128>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010088 <bogus+ 136>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010090 <bogus+ 144>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010098 <bogus+ 152>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100a0 <bogus+ 160>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100a8 <bogus+ 168>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100b0 <bogus+ 176>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100b8 <bogus+ 184>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100c0 <bogus+ 192>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100c8 <bogus+ 200>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100d0 <bogus+ 208>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100d8 <bogus+ 216>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100e0 <bogus+ 224>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100e8 <bogus+ 232>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100f0 <bogus+ 240>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000100f8 <bogus+ 248>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010100 <bogus+ 256>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010108 <bogus+ 264>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010110 <bogus+ 272>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010118 <bogus+ 280>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010120 <bogus+ 288>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010128 <bogus+ 296>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010130 <bogus+ 304>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010138 <bogus+ 312>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010140 <bogus+ 320>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010148 <bogus+ 328>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010150 <bogus+ 336>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010158 <bogus+ 344>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010160 <bogus+ 352>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010168 <bogus+ 360>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010170 <bogus+ 368>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010178 <bogus+ 376>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010180 <bogus+ 384>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010188 <bogus+ 392>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010190 <bogus+ 400>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x0000000000010198 <bogus+ 408>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000101a0 <bogus+ 416>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000101a8 <bogus+ 424>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000101b0 <bogus+ 432>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000101b8 <bogus+ 440>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000101c0 <bogus+ 448>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x00000000000101c8 <bogus+ 456>: 0x51 0x51 0x51 0x51 0x51 0x51 0x00 0x00
0x00000000000101d0 <bogus+ 464>: 0xe0 0x83 0x45 0x75 0xae 0x22 0xf4 0x76
0x00000000000101d8 <bogus+ 472>: 0x93 0xea 0x4e 0x76 0x64 0xf7 0x12 0x00
0x00000000000101e0 <bogus+ 480>: 0xc4 0x01 0x2f 0x00 0x00 0x00 0x2f 0x00
0x00000000000101e8 <bogus+ 488>: 0x00 0x00 0x00 0x00 0x10 0xf7 0x12 0x00
0x00000000000101f0 <bogus+ 496>: 0x09 0x00 0x92 0x00 0x8e 0x07 0x00 0x00
0x00000000000101f8 <bogus+ 504>: 0xfe 0xff 0xff 0xff 0xe0 0x83 0x45 0x75
<bochs:19> c
00017826178i[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00) 《----这个还需要确认下为何
00017826182i[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00)
以上问题发现是代码前后物理地址不一致造成,属于笔误,走读一遍即可发现。
不过修改后发现存在下面悲剧的问题,乱码问题,瞄一眼基本可以判断存在越界读取字符串的问题(还好不是越界写内存)
可是,哪里存在越界读取呢?重新走读了下代码,感觉没啥大问题(当然,只是建立在现有单薄的汇编基础上。。。囧)
SECTION header vstart=0
program_length dd program_end
code_entry dw start ;段内偏移
dd section.code_1.start ;段起始地址
realloc_tbl_len dw (header_end-code_1_segment)/4
code_1_segment dd section.code_1.start
header_end:
SECTION code_1 align=16 vstart=0
start:
mov ax, msg
mov bp, ax
mov cx, 28
mov ax, 0x1301
mov bx, 0x000c
mov dl, 0
int 10h
jmp $
msg: db "byebye loader, here's client"
times 400 db "Q"
program_end
没办法,只能单步大法了,没有太多背景知识,也只能这样子了。。。
火速断点到mov ax,msg处:
<bochs:5> s
Next at t=17826173
(0) [0x0000000000010010] 1001:0000 (unk. ctxt): mov ax, 0x0014 ; b81400
<bochs:6> u /20
00010010: ( ): mov ax, 0x0014 ; b81400
00010013: ( ): mov bp, ax ; 89c5
00010015: ( ): mov cx, 0x001c ; b91c00
00010018: ( ): mov ax, 0x1301 ; b80113
0001001b: ( ): mov bx, 0x000c ; bb0c00
0001001e: ( ): mov dl, 0x00 ; b200
00010020: ( ): int 0x10 ; cd10
00010022: ( ): jmp .-2 ; ebfe
00010024: ( ): bound di, ds:[bx+di+101] ; 627965
00010027: ( ): bound di, ds:[bx+di+101] ; 627965
0001002a: ( ): and byte ptr ds:[si+111], ch ; 206c6f
0001002d: ( ): popa ; 61
0001002e: ( ): jb .+44 ; 6465722c
00010032: ( ): and byte ptr ds:[bx+si+101], ch ; 206865
00010035: ( ): jb .+101 ; 7265
00010037: ( ): daa ; 27
00010038: ( ): jnb .+32 ; 7320
0001003a: ( ): arpl word ptr ds:[si+105], bp ; 636c69
0001003d: ( ): outsb dx, byte ptr gs:[si] ; 656e
0001003f: ( ): jz .+81 ; 7451
<bochs:7>
由反汇编可以看到:字符串的具体段内偏移首地址是0x0014,那么掐指一算,实际物理地址应该就是cs基址*0x10 + 0x0014 = 0x1001 * 0x10 + 0x0014 = 0x10024火速继续dump memory看一把:
<bochs:7> xp /48bx 0x10024
[bochs]:
0x0000000000010024 <bogus+ 0>: 0x62 0x79 0x65 0x62 0x79 0x65 0x20 0x6c
0x000000000001002c <bogus+ 8>: 0x6f 0x61 0x64 0x65 0x72 0x2c 0x20 0x68
0x0000000000010034 <bogus+ 16>: 0x65 0x72 0x65 0x27 0x73 0x20 0x63 0x6c
0x000000000001003c <bogus+ 24>: 0x69 0x65 0x6e 0x74 0x51 0x51 0x51 0x51
0x0000000000010044 <bogus+ 32>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
0x000000000001004c <bogus+ 40>: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51
<bochs:8>
熟悉的0x62出现,没错的呀,就是字符串”byebye。。。”的ascii值呀~~ 怎么看也没有字符串越界读取呀~重新走读了一遍又一遍的代码
无解,无解,无解,无解。
最后,没辙,习惯性的sreg一把,扫一遍所有段寄存器吧:
<bochs:8> sreg
es:0x1000, dh=0x00009301, dl=0x0000ffff, valid=1
Data segment, base=0x00010000, limit=0x0000ffff, Read/Write, Accessed
cs:0x1001, dh=0x00009301, dl=0x0010ffff, valid=1
Data segment, base=0x00010010, limit=0x0000ffff, Read/Write, Accessed
ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ds:0x1000, dh=0x00009301, dl=0x0000ffff, valid=7
Data segment, base=0x00010000, limit=0x0000ffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x00000000000fa1a7, limit=0x30
idtr:base=0x0000000000000000, limit=0x3ff
<bochs:9>
发现唯一有疑点的地方就是ds和cs不一致。一开始不以为然,这个不一致也正常,存在各个段,基址不一样很正常。但是,这个client的代码本身就是一个段,这个让我有点疑点,如果以cs为基址进行偏移,肯定不会存在这种越界读取的问题,难道是这个字符串以ds基址进行offset了?没有任何依据的情况下,走投无路的情况下,大胆猜测也是一种必须,计算一把,如果以ds 0x1000作为基址进行偏移,那么实际进行读取的字符串起始地址为:0x10000+0x0014 = 0x10014,继续dump一把memory,偏移量为28bytes
<bochs:9> xp /48bx 0x10014
[bochs]:
0x0000000000010014 <bogus+ 0>: 0xc5 0xb9 0x1c 0x00 0xb8 0x01 0x13 0xbb
0x000000000001001c <bogus+ 8>: 0x0c 0x00 0xb2 0x00 0xcd 0x10 0xeb 0xfe
0x0000000000010024 <bogus+ 16>: 0x62 0x79 0x65 0x62 0x79 0x65 0x20 0x6c
0x000000000001002c <bogus+ 24>: 0x6f 0x61 0x64 0x65 0x72 0x2c 0x20 0x68
0x0000000000010034 <bogus+ 32>: 0x65 0x72 0x65 0x27 0x73 0x20 0x63 0x6c
0x000000000001003c <bogus+ 40>: 0x69 0x65 0x6e 0x74 0x51 0x51 0x51 0x51
<bochs:10>
发现不对劲了~ 上面标红处出现了熟悉的acsii,再数了一下从第一个0x62前偏移了多少个bytes,刚好有0x10个,而cs和ds刚好也相差0x10,难道真的就是用ds计算这个字符串的偏移?????混蛋!!!
立马修改代码,出事情况下把ds和cs赋成一样(0x1001),见下:
SECTION code_1 align=16 vstart=0
start:
mov ax, cs
mov ds, ax
mov ax, msg
mov bp, ax
mov cx, 28
mov ax, 0x1301
mov bx, 0x000c
mov dl, 0
int 10h
jmp $
但是!但是! 结果还是没有变化。。。。
怒了,怒了,重新回翻下刚才sreg的记录,发现es也是0x1000,然后这个时候才突然发现ES不是用于字符串处理的目的串的基址寄存器吗?
这次小心翼翼的把es也赋成和cs一样(如果还不行,那真的没辙了。。。)
果真!直接运行一把,熟悉的该死的本该出现的字符串终于显示在bochs上了:
附上正确的代码:
SECTION header vstart=0
program_length dd program_end
code_entry dw start ;段内偏移
dd section.code_1.start ;段起始地址
realloc_tbl_len dw (header_end-code_1_segment)/4
code_1_segment dd section.code_1.start
header_end:
SECTION code_1 align=16 vstart=0
start:
;bug-fix: 需要把es,ds和cs统一起来
mov ax, cs
mov ds, ax
mov es, ax
mov ax, msg
mov bp, ax
mov cx, 28
mov ax, 0x1301
mov bx, 0x000c
mov dl, 0
int 10h
jmp $
msg: db "byebye loader, here's client"
times 400 db "Q"
program_end:
心得:
在缺乏足够的知识使用汇编让字符串在终端显示的情况下,终于通过单步大法和大胆胡猜进行定位这个越界显示的问题。这次是运气,有一定的规律可以寻找,下次复杂点估计就歇菜了,所以汇编基础还是得继续夯实,本科大三学习的汇编啊,混蛋,全还回去 了~
最后附上jmp far [0x04]这个含义理解:
Jmp far ds:0x04 实际含义:从ds取出段基址* 0x10,然后再加上0x04偏移,访问该地址为起始地址,长度为2个双字节,其中第一个双字保存到cs中,后一个双字保存到ip中。然后jmp的地址就是cs*0x10
我们来计算下:
1. 首先通过sreg查看ds的内容:为0x1000
<bochs:7> sreg
es:0x1000, dh=0x00009301, dl=0x0000ffff, valid=1
Data segment, base=0x00010000, limit=0x0000ffff, Read/Write, Accessed
cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=3
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ds:0x1000, dh=0x00009301, dl=0x0000ffff, valid=7
Data segment, base=0x00010000, limit=0x0000ffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x00000000000fa1a7, limit=0x30
idtr:base=0x0000000000000000, limit=0x3ff
2. 然后计算 ds:0x04 = 0x1000 * 0x10 +0x04 = 0x10004,所以要取出的实际jmp地址的起始偏移地址为0x10004,接下去要做的就是dump内存,查看实际值:
<bochs:9> xp /10bx 0x10004
[bochs]:
0x0000000000010004 <bogus+ 0>: 0x00 0x00 0x01 0x10 0x00 0x00 0x01 0x00
0x000000000001000c <bogus+ 8>: 0x01 0x10
<bochs:10>
3. 重新排列这2个双字(4字节,32位):见下,越顶上地址越高。得到实际的32位值为:0x10010000,然后把高位的2个字节给cs(0x1001),低位的2个字节给ip(0x0000)
0x10
0x01
0x00
0x00
0x1001 0000
4. 重新排列这2个双字(4字节,32位):见下,越顶上地址越高。得到实际的32位值为:0x10010000,然后把高位的2个字节给cs(0x1001),低位的2个字节给ip(0x0000)
5. 所以jmp far [0x04] === jmp farcs:0x0000 == jmp 物理地址0x1001 * 0x10 = jmp 0x10010,我们预测,跳转后,ds的内容还是为0x1000.cs的内容为0x1001,ip的内容为0x0000,实际情况如下:
<bochs:12> s
Next at t=17826173
(0) [0x0000000000010010] 1001:0000 (unk. ctxt): mov ax, 0x0014 ; b81400
<bochs:13> sreg
es:0x1000, dh=0x00009301, dl=0x0000ffff, valid=1
Data segment, base=0x00010000, limit=0x0000ffff, Read/Write, Accessed
cs:0x1001, dh=0x00009301, dl=0x0010ffff, valid=1
Data segment, base=0x00010010, limit=0x0000ffff, Read/Write, Accessed
ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ds:0x1000, dh=0x00009301, dl=0x0000ffff, valid=7
Data segment, base=0x00010000, limit=0x0000ffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x00000000000fa1a7, limit=0x30
idtr:base=0x0000000000000000, limit=0x3ff
<bochs:14> r
rax: 0x00000000_00001001 rcx: 0x00000000_00090000
rdx: 0x00000000_00000000 rbx: 0x00000000_00000010
rsp: 0x00000000_0000fffe rbp: 0x00000000_00000000
rsi: 0x00000000_000e0064 rdi: 0x00000000_00000000
r8 : 0x00000000_00000000 r9 : 0x00000000_00000000
r10: 0x00000000_00000000 r11: 0x00000000_00000000
r12: 0x00000000_00000000 r13: 0x00000000_00000000
r14: 0x00000000_00000000 r15: 0x00000000_00000000
rip: 0x00000000_00000000
eflags 0x00000012: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf AF pf cf
<bochs:15>