关于某些环境下第二次调用disp_str产生乱码的问题解析

前言 标题中的”某些环境“包括笔者和一些同学的64位系统。 笔者验证时数次得到不符合预期的结果,于是数次推翻之前的结论,一开始以为这仅仅是一个与开关PIC选项有关的问题,后来发现可能是开关PIE的问题,再去实验发现同样的选项在不同编译器版本下行为也不同,可能是不同编译器的行为不同。 本文中关于PIC、PIE的分析比较粗糙,并且笔者的相关知识也很浅薄,可能会有很多错误,希望读者包涵并指正。 问题描述 在进行orange chapter5的第i个实验时,第二个disp_str的输出会变成乱码。原本笔者以为是对输出字符串的修改导致了错误,但经过许多尝试发现即使不做任何修改,只要编译一下原始的代码,第二次disp_str的输出就是乱码。更诡异的是原本附件中的a.img的运行结果是正常的,那么这有可能是编译环境不同,导致出现了问题。 图中可以看到最后一行输出是乱码。 问题溯源 为了方便查看,笔者只将start.c编译到start.o,其中第一次调用disp_str的部分是这样的: 比较有意思的是__x86_get_pc_thunk_bx函数,它的内容是这样的: public __x86_get_pc_thunk_bx __x86_get_pc_thunk_bx proc near ; __unwind { mov ebx, [esp+0] retn ; } 这个函数跟软件安全课程中介绍的病毒获取自身代码段位置的代码一样,是一种实现PIE(position-independent Executable,位置无关可执行文件),因为call指令相当于push ip; jmp。下一句紧接着执行mov ebx, [esp+0];retn就会将刚压进栈的ip的值赋给ebx。此时ebx的值是add ebx, (offset _GLOBAL_OFFSET_TABLE)的地址。所以下一句的add就会让ebx的值变为_GLOBAL_OFFSET_TABLE的值了,后续的字符串都是相对此时的ebx寻址的。 从lea指令开始为第一次调用disp_str布置参数,将[ebx]+aCstartBegins-_GLOBAL_OFFSET_TABLE_也就是aCstartBegins的实际地址压入栈中。 这段代码这么做是因为aCstartBegins和_GLOBAL_OFFSET_TABLE_的相对偏移是固定的,但程序本身的装载地址会发生变化,为了实现位置无关需要运行时获取代码所在的地址。 于是第一次调用十分正常,在disp_str中下断点,在bochs中调试: 看到正常的ebx的值应该是0x32ff4,此时aCstartBegins的地址是0x31000。 继续到第二次调用disp_str,用调试器或者静态分析都可以看到,正确的字符串aCstartEnds地址应该是aCstartBegins+0x2a=0x3102a。 ebx的值变成了0x32fa0=0x32ff4-0x54,导致disp_str显示字符串的地址变成了0x30fd6=0x3102a-0x54。 既然ebx的值改动了,浏览start.o的反汇编结果也没有发现ebx被改动,并且两次disp_str调用紧邻着也会输出乱码,那就只有可能是disp_str中本身修改了ebx. disp_str: push ebp mov ebp, esp xchg bx, bx # magic_break for debug mov esi, [ebp + 8] ; pszInfo mov edi, [disp_pos] mov ah, 0Fh .1: lodsb test al, al jz .2 cmp al, 0Ah jnz .3 push eax mov eax, edi mov bl, 160 ; <--------------修改bl div bl and eax, 0FFh inc eax mov bl, 160 ; <--------------修改bl mul bl mov edi, eax pop eax jmp .1 .3: mov [gs:edi], ax add edi, 2 jmp .1 .2: mov [disp_pos], edi pop ebp ret 发现代码中两次修改ebx的值,都是将bl(ebx低8位)改为160,也就是16进制的0xa0. 再根据先前的ebx从0x32ff4变成0x32fa0,正好是低8位从0xf4变成了0xa0,出错过程完全分析清楚。 ...

October 22, 2024 · 1 min · 206 words · JuicyMio

clangd异常闪退原因分析

背景 使用neovim打开一个pwn题给的main.c源码的时候,clangd直接exit 1退出。当时的目录是这个样子的: ❯ ls ld-linux-x86-64.so.2 libc.so.6 main.c pwn 然后我找到了clangd的目录,执行./clangd,一切正常。 又打开了几个其他的c语言代码测试,一切正常。 把main.c复制到其他目录下,打开仍然一切正常。 看来问题出在clangd在处理这个特定目录下的文件时会闪退。于是我在这个目录下执行/path/to/clangd。复盘一下大概是这个样子的: ❯ /tmp/clangd_17.0.3/bin/clangd /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/libpthread.so.0) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/libpthread.so.0) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/librt.so.1) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/librt.so.1) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/libdl.so.2) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/libdl.so.2) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/libm.so.6) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/libm.so.6) 本机系统为archlinux,Glibc版本为2.39,而题目目录下的libc.so.6版本为2.35。有经验的读者应该已经看出问题所在了。 ...

April 5, 2024 · 2 min · 388 words · JuicyMio

hugo_with_obsidian

背景 由于obsidian和hugo的图片路径十分不兼容(obsidian支持Vault内的绝对路径或文章相对路径,而hugo会把static内的图片放到public,也就是网站根目录下),如果把图片和md文件放在同一目录下倒是方便一点,但是这样目录就太乱了,令人难以接受。最简单的方案是统一把图片传到图床,但我一是囊中羞涩,二是常常要断网打比赛,需要笔记的图片保存在本地,不能使用图床的方案。总之我拖了好久都没处理这个问题,现在觉得不得不解决了。 图片复制与链接修正 因为懒,所以先去搜了一下有没有插件可以一键解决。然后浪费了一上午时间测试各种插件,不是修复图片链接不方便就是迁移图片位置不好调整。最后一想,我自己会写代码,还有chatgpt, 为什么要学插件怎么用折磨自己… 于是搓了个很糙但是能用的版本。以下代码基本上是chatgpt生成的,就改了一下路径。 #!/bin/python3 import sys import glob import shutil blog_dir = "/home/juicymio/blog/blog_papermod/" source_dir = "/home/juicymio/notes/PWN!!!/" attachments_folder = source_dir + "attachments" target = sys.argv[1].strip(".md") static_dir = blog_dir + "static/" def copy_files(source_dir, dest_dir, pattern): search_pattern = source_dir + "/" + pattern file_paths = glob.glob(search_pattern) for file_path in file_paths: dest_path = dest_dir + "/" + file_path.split("/")[-1] shutil.copy2(file_path, dest_path) copy_files(attachments_folder, static_dir, target + "*") source_path = source_dir + target + ".md" post_path = blog_dir + "content/posts/" + target + ".md" shutil.copy2(source_path, post_path) def adjust_path(file_path, target_string, adjusted_string): with open(file_path, "r") as f: content = f.read() updated_content = content.replace(target_string, adjusted_string) with open(file_path, "w") as f: f.write(updated_content) return adjust_path(post_path, "![](", "![](") 需要使用obsidian的Paste image rename第三方插件把插入的图片名字改成{{fileName}}-1.jpg的形式,并设置obsidian的图片存放路径和图片链接格式(attachments这个名字随便改)。这样python脚本就可以把attachments里所有以{{filename}}开头的文件复制到hugo site的/static目录下,并把md文件中的![]attachments/*修正为![]/*。 使用方法: ./publish.py hugo_with_obsidian.md 非常好用。 模板 以上虽然解决了图片的问题,但是直接复制的md并没有头部的Front Matter,研究了一下(经xxw指点)发现可以使用obsidian的Template功能。在设置里给Insert Template分配一个快捷键可以让操作更加丝滑,我设置为了Alt+T。 设置template的目录,这里设置成templates,即Vault下的templates文件夹。 向template/posts中添加如下内容,变量可以根据使用的主题自行增减。 --- title: "{{title}}" author: ["JuicyMio"] date: "{{date}}" tags: draft: false ShowToc: "true" description: "" --- 在md文件中按Alt+T,选择posts,即可一键添加Front Matter. ...

April 1, 2024 · 1 min · 139 words · "JuicyMio"

开启linux kernel rust support

背景 试图用Rust做操作系统小组作业,某组员遇到环境配置问题。我尝试了一下,发现网上中文资料确实比较少,而且官方文档翻译略有过时。(可能有Rust更新比较快的原因。于是写了篇没什么用的流水账记录一下编译一个启用Rust支持的Linux kernel的过程。 环境配置 本文所述内容均在archlinux下进行。 Rust: 参照官方文档配置一下rust相关环境。 LLVM 省流版(不保证完全准确,在我这能跑): 从 https://www.kernel.org/ 下载linux-6.8.2源码 在linux-6.8.2目录下切换rustc版本 rustup override set $(scripts/min-tool-version.sh rustc) 添加rust-src rustup component add rust-src 安装bindgen-cli 注意:此处中文文档已经滞后,需要安装的是bindgen-cli而非bindgen. 详见: https://github.com/rust-lang/cargo/issues/11249 cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen-cli 需要将~/.cargo/bin添加到环境变量 生成rust-analyzer配置文件 make LLVM=1 rust-analyzer 查看rust工具链是否符合要求 make LLVM=1 rustavailable 在我这的输出是(我没锁bindgen版本) ❯ make LLVM=1 rustavailable *** *** Rust bindings generator 'bindgen' is too new. This may or may not work. *** Your version: 0.69.4 *** Expected version: 0.65.1 *** *** *** Please see Documentation/rust/quick-start.rst for details *** on how to set up the Rust support. *** Rust is available! 然后就可以编译内核了 ...

April 1, 2024 · 1 min · 142 words · JuicyMio

天选4Archlinux安装及使用小记

背景 Laptop:华硕天选4锐龙版 CPU:AMD Ryzen 7940H GPU:Radeon 780m Graphics + NVIDIA RTX 4060 Laptop 安装过程主要参考archlinux 简明指南 (icekylin.online) 由于要在win11的D盘切分出来一块空间(好不容易清出来的200G)安装,没办法使用archinstall脚本。(archinstall的分区方案只会分配一整块硬盘,差点把我D盘数据全清了)。 双显卡驱动 仍然按照archlinux 简明指南 (icekylin.online)进行操作。 安装nvidia闭源驱动时出现了各种问题,但是不装闭源驱动又经常卡死,尤其是我的双屏还需要独显输出,于是在timeshift数次之后终于艰难地驯服了双显卡驱动。使用了下面知乎老哥的方案:不安装optimus-manager,仅使用华硕提供的supergfxctl进行显卡切换。猜测optimus-manager使用Xorg进行切换和Wayland一起使用可能会出现卡死等问题,笔者暂且没有能力验证。 华硕天选5Pro使用Win11+ArchLinux双系统 - 知乎 (zhihu.com) sddm改为使用wayland启动(其实没什么意义,而且sddm的wayland支持尚不稳定)。 Kernel mode setting - ArchWiki (archlinux.org) 输入法 只装了个最基础的fcitx5就没管了。 WPS等软件中无法使用输入法: https://wszqkzqk.github.io/2024/03/09/WPS-Fcitx5/ 字体 不知道怎么同时配置中文字体和英文字体,装了教程里的一堆字体之后,暂时摆了。 KDE 由于刚刚更新Plasma6,很多插件,主题还没有更新。(悲) 打算搞一套仿Mac的主题玩。 upd: 使用了Apple-Sonoma-Dark (KDE6的主题更新的还是很快的,给大佬点赞 GTK主题 White-Sur,跟全局主题尽量像一点。 桌面特效 窗口(比如Konsole)的透明度,模糊等配置在这里。 终端 Shell: zsh + zim + powerlevel10k, 常用插件装上 Terminal Emulator: Konsole Konsole好丑,想换。 alt+n会new tab,跟我钟爱的zellij冲突了。看了keyboard shortcut里没有这个快捷键,然后发现是按住alt+某个字母会触发toolbar上以该字母为首字母的功能(New Tab) 。。。索性直接把toolbar关了,反正也没什么用还丑。 zellij不知道为什么不能alt+方向键了。。。好在还能alt+hjkl zellij不能粘贴:config.kdl里修改copy_command为wl-copy NeoVim 下了个LazyVim,被眼花缭乱的功能吓晕,不过感觉可能习惯一下+关一些没用的东西之后会比LunarVim好用。 upd: LunarVim已停止更新 Terminal-Multiplexer zellij 很好用,但是也有一定问题: 快捷键alt+hjkl是切换pane, nvim中shift+hl是切换buffer,ctrl+hjkl是切换split的windows,相当手忙脚乱。并且在用ctrl组合快捷键的时候需要ctrl+g把zellij的快捷键锁起来。 nvim中显示中文(以及其它多字节字符)有问题。提了个issue ...

March 26, 2024 · 1 min · 113 words · JuicyMio