吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 10467|回复: 199
上一主题 下一主题
收起左侧

[汇编] 你没看错:动手开发GUI简单操作系统(一)

    [复制链接]
跳转到指定楼层
楼主
TLHorse 发表于 2021-2-10 18:06 回帖奖励
本帖最后由 TLHorse 于 2021-2-11 18:18 编辑

你没看错:动手开发GUI简单操作系统(一)
你没看错:动手开发GUI简单操作系统(二)
正在更新……

前言

今天我终于想好发布这篇文章,以前自己一直在摸索开发,保证100%原创。这个操作系统异常简单,没有Windows的高级,没有OS X的华丽,更没有Linux的强大——也别指望了,对于个人来说根本没多少生产力,只能用来学习知识,自己整着玩。但是,OS开发的资料太少了,“你没看错”系列中的每一行代码,确实是作者我本人摸滚打爬才得来的。

或许我的文字在各位大佬眼中会很简单。所以说,我尽力吧,简明易懂,不加废话。如果有不专业的地方,直接留言改正,谢谢。

我准备出一系列“你没看错”文章,一定会有后续的。OS一篇文章讲不完,我的写法是理论和实践相辅相成,一点点讲。

学习目标

第一天我们的目标很简单,主要是写启动扇区:

  1. 实现在启动扇区打印字符串
  2. 在启动扇区打印地址
  3. 添加读取磁盘的功能

这些实现主要是为以后加载内核、出现错误调试做准备。

要求知识

  1. 汇编语言不要求精通,但一定要熟悉,有基本了解;
  2. C语言要会,写内核要用;
  3. shell必须会敲命令,没得说;
  4. 可以先修一些附加技能,比如gdb、Makefile等,也可以先了解相关概念。

环境配置

在开发之前,我们需要配置开发环境。我使用的是Mac,终端用的是zsh。如果有能力,可以用Linux,因为Linux包含开发过程中大部分的工具。如果是Windows……那就去论坛下载个虚拟机,使用Linux吧。为了不让诸位一上来就被各种安装震慑住,我们开发一点安装一点。首先(假设你有Homebrew,一定要换源):

brew install qemu nasm # 怎么样?很简单吧

简单认识一下:qemu是个开源的模拟器,nasm是Netwide汇编编译器。

加载启动扇区

我们的操作系统,从bootsector写起。这个bootsector是个启动扇区。当这个分区被识别有效后,系统就会启动。我们的首要目标是创建能被识别的bs。

为了检测磁盘是可启动的,BIOS会检测第511和512字节是否为十六进制AA55。记住0xAA55,这个数字是硬件开发者所设置的。

新建你的项目文件夹,给你自己的系统起个名字,比如我的叫Venus。创建bootsect.asm

loop:
    jmp loop ; 开始递归,在这里做无限循环。其实也可以用hlt或者jmp $实现。

times 510 - ($-$$) db 0 ; 在bs前放上510个0
dw 0xAA55 ; 在第511字节处,定义0xAA55,覆盖两个字节

我们编译、模拟两步走:

$ nasm -fbin boot_sect.asm -o boot_sect.bin 
$ qemu-system-x86_64 boot_sect.bin # 如果错误,改成qemu boot_sect.bin


至此,你迈开了第一步!系统在引导之后,进入了无限循环。

输出至屏幕

先来了解一下中断:

在点击鼠标或键盘时(正如我现在在做的事情),计算机会立即给我反馈处理结果,计算机与我们之间是在进行实时交互的。而实时性的实现便是依赖了中断,中断是为了顺应人们对实时性交互的需求而产生的技术。中断之所以有用,是因为它会立刻停下当前的程序(软件)去做另外一件事。

我们希望启动后,让系统在屏幕上输出几个字符:'Venus'。我们需要用到int 0x10。这个中断用于控制屏幕输出,它好比一个约定俗成的函数,有两个参数,ax寄存器的低位al就是要输出的字符,高位ah就是控制输出模式的指示符。代码如下:

mov ah, 0x0E ; 指示符为0x0E代表tty模式(你应该知道tty是什么,TeleTYpe)
mov al, 'V'  ; 把al赋值'V'
int 0x10     ; 终端输出
mov al, 'e'  ; 重复以上流程
int 0x10
mov al, 'n'
int 0x10
mov al, 'u'
int 0x10
mov al, 's'
int 0x10

jmp $

; BIOS识别的数字
times 510 - ($-$$) db 0
dw 0xAA55 

我们编译、模拟两步走:



完善打印功能

为了方便我们今后的调试,我们需要完善打印功能,这样出了什么差错直接print就OK了。我们的打印分为两种:打印字符串和打印地址。

打印字符串

都知道,C语言中的字符串结构长这样:

"Venus" -> 'V' 'e' 'n' 'u' 's' '0x0'

都是几个字符再加上一个空字节0x0。如果要打印字符串,而不是单个字符,在汇编里面,可以对应成一个栈来处理。同目录新建一个print.asm

print:
    pusha ; 将所有东西压入栈

; 记住:一直循环打印栈的字符,直到碰到字符串末0x0
; while (string[i] != 0) { print string[i]; i++ }

start:
    mov al, [bx] ; bx相当于字符串参数,是字符串的首位
    cmp al, 0    ; al和0比较
    je done      ; 如果相等,就到了字符串末尾,跳转到结束done

    mov ah, 0x0E ; 如果不相等,开始打印,先进入tty模式
    int 0x10     ; 直接中断。因为al参数已经有字符了

    add bx, 1    ; 如果你把这个栈+1,相当于地址后移一位,这样再打印就是下一个字符串
    jmp start    ; 递归

done:
    popa         ; 弹出栈  
    ret          ; 返回主程序

我们再空几行,实现一个附加功能——换行:

print_nl:        ; print NewLine
    pusha

    mov ah, 0x0E ; tty模式
    mov al, 0x0A ; 把0x0A和0x0D合起来相当于\n
    int 0x10
    mov al, 0x0D ; 把0x0A和0x0D合起来相当于\n
    int 0x10

    popa
    ret

打印地址(4位)

打印地址也很有用的。但它涉及到一个把指定字符转换为ASCII的问题。因为传入的参数不是带引号的字符串,而是譬如0x1234这样的地址,那到底应该打印什么呢?转换方法如下:

字符与ASCII对应关系

数字转换:0~9是0x30~0x39,所以把数字加上0x30即是ASCII;
字母转换:A~F(当成1~6)是0x41~0x46,所以把字母加上0x40

代码

print_hex:
    pusha
    mov cx, 0 ; cx在循环指令和重复前缀中,作循环次数计数器

; 参数dx:要打印的地址
hex_loop:
    cmp cx, 4 ; cx是不是已经循环了四次?
    je end    ; 如果是,跳转到end结束

    ; 如果不是:开始处理

    mov ax, dx     ; 在ax上对字符处理,(dx是我们的地址参数)
    and ax, 0x000F ; 先把这个地址只保留最后一位。比如0x1234就变成0x0004
    add al, 0x30   ; 加上30,这样4就会变成ASCII:34(别忘了这个al是ax的一部分,是一个寄存器——
    cmp al, 0x39   ; 如果发现这个数字>9,不是0~9,那么这个数字就是字母,加上7,就会是A~F中的一个
    jle step2      ; Jump if Lower or Equal:al小于等于0x39跳转至step2
    add al, 7

step2:
    ; 第二步:我们的ASCII字符应该放在哪个地址呢?
    ; 地址BX:基地址+字符串长度(5位,别忘了还有最后的0x0)-字符索引
    mov bx, HEX_OUT + 5 ; 基+长
    sub bx, cx          ; -索引
    mov [bx], al        ; 把al中的字符移到[bx],中括号表示地址的内容
    ror dx, 4           ; ROll Right:0x1234 -> 0x4123 -> 0x3412 -> 0x2341 -> 0x1234. ror帮我们实现类似遍历字符串的效果。你可以去掉这行指令,看看会发生什么

    add cx, 1           ; 循环计数器+1
    jmp hex_loop        ; 回到循环

end:
    mov bx, HEX_OUT     ; 把HEX_OUT设置到bx里,作为下一个call的参数
    call print          ; 调用写好的print.asm

    popa
    ret

HEX_OUT:
    db '0x0000', 0 ; 这是我们输出的地址,先定义下来

尝试使用打印功能

编写bootsect.asm

[org 0x7C00]

mov bx, GREETINGS ; 设置参数
call print        ; 打印
call print_nl     ; 换行

mov dx, 0x4567    ; 设置参数(地址)
call print_hex    ; 打印十六进制

mov bx, SHUTDOWN  ; 同上
call print
call print_nl

jmp $             ; 挂起程序,无限循环(hlt也行)

%include "boot_sect_print.asm"
%include "boot_sect_print_hex.asm"

; 定义两个数据,注意末尾一定要带0字节
GREETINGS:
    db 'Welcome to Venus', 0

SHUTDOWN:
    db 'Shutdown', 0

times 510-($-$$) db 0
dw 0xAA55

说明两个地方:

  1. [org 0x7C00]:org是用来设置程序基址的。因为BIOS将bs加载到0x7C00的位置,所以我们设置基址为0x7C00。这行指令的中括号去掉也行。
  2. %include:用来引用文件,后面跟上空格和双引号,双引号里写文件名称。值得注意的是,%include命令相当于把引用的文件直接替换到程序中,不做任何操作。

还是按老办法编译、模拟:



读取磁盘

好了,最枯燥却最有用的功能来了,读取磁盘。我们总不能神经质地把整个系统都放在启动扇区。我们先了解一下磁盘(这个部分必须看):

磁盘基础

盘片、片面和磁头



硬盘中一般会有多个盘片组成,每个盘片包含两个面,每个盘面都对应地有一个读写磁头。受到硬盘整体体积和生产成本的限制,盘片数量都受到限制,一般都在5片以内。盘片的编号自下向上从0开始,如最下边的盘片有0面和1面,再上一个盘片就编号为2面和3面。

扇区(sector)和磁道(track)



上图显示的是一个盘面,盘面中一圈圈灰色同心圆为一条条磁道,从圆心向外画直线,可以将磁道划分为若干个弧段,每个磁道上一个弧段被称之为一个扇区(图践绿色部分)。扇区是磁盘的最小组成单元,通常是512字节。(由于不断提高磁盘的大小,部分厂商设定每个扇区的大小是4096字节)。

磁头(head)和柱面(cylinder)



硬盘通常由重叠的一组盘片构成,每个盘面都被划分为数目相等的磁道,并从外缘的“0”开始编号,具有相同编号的磁道形成一个圆柱,称之为磁盘的柱面。磁盘的柱面数与一个盘面上的磁道数是相等的。由于每个盘面都有自己的磁头,因此,盘面数等于总的磁头数。

开始读取吧!

我就直接放代码了,没什么技术含量,只不过有一些关键的寄存器数值与中断号码需要明白:

; 参数:
;   - dh:扇区个数
;   - dl:磁盘
; 读取的数据存入es:bx

disk_load:
    pusha              ; 压入栈
                       ; 将dx也压入栈
    push dx            ; dx一会会被读取磁盘的操作覆盖,所以先压入栈保存

    mov ah, 0x02       ; BIOS 读取扇区的功能编号
    mov al, dh         ; AL - 扇区读取个数,也就是我们的dh
    mov cl, 0x02       ; CL - 从哪里开始读取,因为第一个扇区是启动扇区,所以这里是0x02
    mov ch, 0x00       ; CH - 柱面编号(0x0-0x3FF)
    mov dh, 0x00       ; DH - 磁头编号(0x0-0xF)

    int 0x13           ; 读取磁盘的中断标号
    jc disk_error      ; Jump if Carry:如果CF被设置,就是出现了错误,跳转

    ; 如果没有错误
    pop dx             ; dx我们用完了,弹出栈
    cmp al, dh         ; 此时bios会把al设置为扇区个数,对比一下
    jne sectors_error  ; 如果两者不一样,读取扇区出现了错误,跳转
    popa               ; 如果一样,停止程序
    ret

; 剩下的是错误处理部分,大家都明白
disk_error:
    mov bx, DISK_ERROR
    call print
    call print_nl
    mov dh, ah
    call print_hex
    jmp disk_loop

sectors_error:
    mov bx, SECTORS_ERROR
    call print

disk_loop:
    jmp $

DISK_ERROR: db "Disk read error", 0
SECTORS_ERROR: db "Incorrect number of sectors read", 0

我们将启动扇区代码bootsect.asm做出如下更改:

[org 0x7C00]
mov bp, 0x8000 ; 把栈顶设成0x8000,这样不与BIOS相干
mov sp, bp     ; 同上
mov bx, 0x9000 ; es:bx == 0x0000:0x9000 == 0x09000

; 现在我们要设置disk_load参数
mov dh, 2 ; 读取两个扇区
; 此处不用设置dl,BIOS已经帮我们设置过了
call disk_load ; 调用

mov dx, [0x9000] ; 获取第一扇区
call print_hex
call print_nl

mov dx, [0x9000 + 512] ; 获取第二扇区(注意偏移地址,跟下面数据对应)
call print_hex

jmp $

%include "print.asm"
%include "print_hex.asm"
%include "disk.asm"

times 510 - ($-$$) db 0
dw 0xAA55

; 上面是bs(第一个扇区)
times 256 dw 0x1234 ; 第2
times 256 dw 0x5678 ; 第3
; 上面的第二第三也不一定,因为有的磁盘一个扇区512,现在有的4096
; …………


后记

别着急,这只是第一天呢,离加载内核还远着呢,项目里只有四个文件。我给大家指指路,我们已经可以读取磁盘,接下来我们需要:

  1. 加载启动扇区
  2. 读取磁盘,加载内核
  3. 从命令行转成GUI图形界面
  4. 设置GDT(代码最简单,但是最困难的部分,也消耗了我的大部分研究时间)
  5. 切换到32bit保护模式
  6. 执行内核:kernel_main
  7. 正式切换到C语言!

剩下的几个步骤我会划分成几天的内容,发布文章讲解。

其实我写着写着突然想到这不就跟革命斗争一样吗,在执行内核前是多么煎熬,执行内核切换C语言后跟解放了一样。

一点点来吧。

相信我!一定有后续!!!很快就出

THE END

点评

大神就是大神,这不是螺丝刀刻系统盘的那位么?赞  发表于 2021-2-19 10:36
加油!别在意那些瞎BB的人!!沉在坛里这么多年,没见多少个发这类技术贴的(没能力?没时间?)  发表于 2021-2-10 23:50

免费评分

参与人数 194吾爱币 +210 热心值 +176 收起 理由
ycc926 + 1 + 1 用心讨论,共获提升!
ma4907758 + 1 热心回复!
zmcom + 1 + 1 用心讨论,共获提升!
m1n9yu3 + 1 + 1 谢谢@Thanks!
miranda0131 + 1 + 1 热心回复!
2286624681 + 1 + 1 热心回复!
1051496412 + 1 + 1 我很赞同!
52poze + 1 + 1 感谢楼主分享原创作品
千囚栀愿^_^ + 1 + 1 用心讨论,共获提升!
plasniper + 1 + 1 我很赞同!
itfanr + 1 我很赞同!
Nachtmusik + 1 感谢您的宝贵建议,我们会努力争取做得更好!
aiosnt + 1 正道的光
gogobn + 1 + 1 支持楼主写个类似ntoskrnl.exe出来
eihouwang001 + 1 + 1 大佬,牛。。。。
xuexixiaobai + 1 + 1 受教了,加油
zqguang3708 + 2 + 1 大佬牛逼!!!!
我真的很狂哦 + 1 + 1 热心回复!
laughingsir38 + 1 + 1 热心回复!
瞧丶王先森 + 1 + 1 用心讨论,共获提升!
baifaxiaolaotou + 1 热心回复!
5721 + 1 + 1 我很赞同!
喜提菜鸟一枚qwq + 1 + 1 用心讨论,共获提升!
宅の士 + 1 用心讨论,共获提升!
zls黑战魔 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
13171595977 + 1 + 1 用心讨论,共获提升!
873934580 + 1 加油加油
hollow + 1 用心讨论,共获提升!
Henny + 1 用心讨论,共获提升!
48433abc + 1 + 1 我很赞同!
玉米诱惑 + 1 + 1 用心讨论,共获提升!
陆先生 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lcd1990 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
503671998 + 1 + 1 牛逼就完事了
victos + 1 + 1 谢谢@Thanks!
yipwing + 1 + 1 谢谢@Thanks!
52pojie61022109 + 1 + 1 我很赞同!
魔道书生 + 2 + 1 在努力学习了
ming1332236 + 1 + 1 我很赞同!
buyouyuan + 1 + 1 谢谢@Thanks!
lyslxx + 1 + 1 我很赞同!
Nasilap + 1 + 1 我很赞同!
泉水叮咚石头 + 1 + 1 我很赞同!
战国 + 1 + 1 热心回复!
r4yn + 1 + 1 谢谢@Thanks!
luochunyan + 1 + 1 谢谢@Thanks!
qin25836 + 1 + 1 这才是真正的技术贴,毫无水分的干货。
文姐姐 + 1 我很赞同!
qzh8008110 + 3 + 1 虽然看不懂,但是楼主很费心机的去写了这篇帖子,很值得学习
Justcodes + 1 + 1 给大佬点赞!
不被承认的好人 + 1 + 1 用心讨论,共获提升!
manyou + 1 + 1 鼓励转贴优秀软件安全工具和文档!
夹克油 + 1 也许不行,但你在努力,有些人不努力只在哔哔!
hxdfree + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Brantini + 1 + 1 我很赞同!
SaberLove + 1 + 1 我很赞同!
毁我容颜 + 1 + 1 我很赞同!
xyhallo + 1 + 1 我很赞同!
zyhaan + 1 + 1 用心讨论,共获提升!
yanggo + 1 好像30年前很流行自己整操作系统!那时应该是有很多开源的代码?
ChenFanthon + 1 + 1 跟着大佬学习
secjia + 1 + 1 我很赞同!
nikolazero + 1 + 1 热心回复!
gaothink + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
拔剑不知谁为雄 + 1 + 1 谢谢@Thanks!
shuhaohi + 1 用心讨论,共获提升!
WAlitudealiy + 1 + 1 谢谢@Thanks!
Cin_Ata + 1 热心回复!
等你回眸 + 1 + 1 用心讨论,共获提升!
奥怪 + 1 + 1 用心讨论,共获提升!
Edison_zhu + 2 + 1 大神,难道你就是传说中螺丝刀刻系统盘的那位?
iamshy520 + 1 + 1 用心讨论,共获提升!
过往温柔的你 + 1 我很赞同!
SocketPair + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
小Jamie + 1 我很赞同!
叙隐微觉 + 1 + 1 我很赞同!
ArGuard + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zsr849408332 + 1 + 1 谢谢@Thanks!
zspzwal + 1 + 1 我很赞同!
schedule + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
a10036pj + 1 我很赞同!
风语毅 + 1 谢谢@Thanks!
ccc12138 + 1 + 1 用心讨论,共获提升!
喜欢躺着玩手机 + 1 + 1 谢谢@Thanks!
colirex + 1 + 1 谢谢@Thanks!
solly + 1 + 1 用心讨论,共获提升!
魅惑小鬼 + 1 + 1 用心讨论,共获提升!
yixi + 1 + 1 谢谢@Thanks!
zhupf + 1 + 1 谢谢@Thanks!
xyl52p + 1 + 1 这个有点厉害了,期待后续!
jackcui + 1 + 1 谢谢@Thanks!
txl + 1 + 1 这种帖子必须顶!
sup999 + 1 + 1 期待后续
chenmg + 2 + 1 好家伙,我直接好家伙
TCP404 + 1 + 1 用心讨论,共获提升!
Ephraim2020 + 1 + 1 你好,世界,我来了
万一赢了呢 + 1 + 1 我很赞同!
maobaozhi + 1 + 1 用心讨论,共获提升!
kfchen21 + 1 + 1 谢谢@Thanks!
wibus + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

  • · Aarow|主题: 1689, 订阅: 282

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
涛之雨 发表于 2021-2-10 19:19
TLHorse 发表于 2021-2-10 18:14
啊?似乎我这篇文章写得很失败

我失望极了 查看82 回复4

好的作品需要时间来检测,而不是多少人查看和多少人去回复。
与其满眼都是回复“感谢楼主”,“学到了,感谢”之类的灌水(注:论坛禁止恶意灌水!)还不如看到几个回复都是认真阅读后的感悟或是疑问等。
(小声逼逼估计很多人也像我一样看不懂,不敢说话,自己写操作系统这种东西太过高深,过于遥远。。。)

点评

大佬是没有时间打字的,比如我!  详情 回复 发表于 2021-2-12 17:37

免费评分

参与人数 2吾爱币 +1 热心值 +2 收起 理由
hsanren + 1 + 1 谢谢@Thanks!
我是不会改名的 + 1 我很赞同!

查看全部评分

推荐
networkdwl 发表于 2021-2-10 21:59
推荐
从0开始的小小怪 发表于 2021-2-11 12:05
TLHorse 发表于 2021-2-10 22:49
好的,你们推荐的东西,我一定学习学习,毕竟在下也不是什么高级人才,也是个小白
没有GUI咱不怕,毕竟g ...

https://github.com/chyyuu/os_course_info 这是总览,东西还是挺多的,期待你的后续

免费评分

参与人数 3吾爱币 +3 热心值 +3 收起 理由
agi学习者 + 1 + 1 谢谢@Thanks!
fengbolee + 1 + 1 用心讨论,共获提升!
TLHorse + 1 + 1 谢谢@Thanks!

查看全部评分

推荐
MSLOS 发表于 2021-2-10 19:32
TLHorse 发表于 2021-2-10 19:18
技术就是拿来折腾的
不管怎么样,现在许多台式机启动还都是传统BlOS,mbr这类的啊

应该叫兼容传统MBR启动, 自从15年以后的PC几乎都是uefi模式启动的多
推荐
testunpack 发表于 2021-2-10 18:57
反正我也看不懂。。。。。
推荐
高山小溪美人 发表于 2021-2-10 18:29
火鉗流氓
推荐
 楼主| TLHorse 发表于 2021-2-10 19:21 |楼主
涛之雨 发表于 2021-2-10 19:19
好的作品需要时间来检测,而不是多少人查看和多少人去回复。
与其满眼都是回复“感谢楼主”,“学到了, ...

好,你这回复给了我不少信心啊,一定坚持
推荐
RemMai 发表于 2021-2-10 18:12
你以为我看的懂?
3#
 楼主| TLHorse 发表于 2021-2-10 18:14 |楼主
本帖最后由 TLHorse 于 2021-2-10 18:29 编辑
RemMai 发表于 2021-2-10 18:12
你以为我看的懂?

啊?似乎我这篇文章写得很失败

我失望极了 查看82 回复4

点评

好的作品需要时间来检测,而不是多少人查看和多少人去回复。 与其满眼都是回复“感谢楼主”,“学到了,感谢”之类的灌水(注:论坛禁止恶意灌水!)还不如看到几个回复都是认真阅读后的感悟或是疑问等。 (小声逼  详情 回复 发表于 2021-2-10 19:19
4#
ashi876 发表于 2021-2-10 18:18
行吧,目前还看不出什么。静待后篇
5#
 楼主| TLHorse 发表于 2021-2-10 18:20 |楼主
ashi876 发表于 2021-2-10 18:18
行吧,目前还看不出什么。静待后篇

好,我一定努力,
其实后面那几部分源代码我都写出来了,就差写文章的事了
7#
E式丶男孩 发表于 2021-2-10 18:30
等着看后续,如果可以的话就该动手了
8#
_paopao 发表于 2021-2-10 18:49
期待后续~
10#
liuchenxii 发表于 2021-2-10 18:58
大哥加油,虽然我啥都看不懂,但还是想看看大哥的后续
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2021-2-25 04:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表