文本乱码编码修复全攻略,新手也能轻松上手!

文本乱码编码修复全攻略,新手也能轻松上手!

咱在处理文本的时候,要是碰到乱码问题,别着急,下面这些方法保准能帮上忙,而且都是一步步详细说明的,新手友好哈。开启自动猜测编码(推荐)这个方法简单又好用,就像给电脑一个小提示,让它自己猜猜看文本该用啥编码打开。打开设置:大家在键盘上同时按下 Ctrl + , 键,这时候就会弹出设置界面啦,你能看到好多设置选项。这一按,就像打开了一个神奇的工具盒子,里面都是能帮咱解决问题的宝贝。搜索相关设置:在设置界面顶部有个搜索框,咱在里面输入 Auto Guess Encoding,就像在大仓库里找特定的宝贝,输入名字,一下子就能定位到啦。勾选相关选项:搜索之后,找到 Files: Auto Guess Encoding 这个选项,把前面的小框框勾选上。这样就大功告成咯,电脑会自动尝试猜测编码,乱码问题说不定就解决啦。终极解决办法(全量强制 GBK)要是上面那个方法还不行,咱就用这个大招,直接强制让文件都按 GBK 编码来读取。新建文件夹:在你当前打开的文件夹的最上头(也就是根目录),新建一个文件夹,给它取个名字叫 .vscode。这就好比在一个大房间里,又隔出了一个小房间专门放特定的东西。新建文件:在刚才建好的 .vscode 文件夹里,再新建一个文件,名字叫做 settings.json。这就像在小房间里又摆了一个小盒子,用来装重要信息。复制粘贴配置并保存:把下面这段神奇的配置复制到 settings.json 文件里,然后保存起来。{ "files.encoding": "gbk", "files.autoGuessEncoding": false }保存好之后,项目里那几百个文件就都乖乖地按 GBK 规范来读取啦,不管是你自己看,还是侧边栏的 AI 看,所有文件里的中文都能正常显示咯。关闭 VS Code 软件自动更新有时候软件自动更新可能会带来一些小麻烦,咱先把它关掉,这样能省不少心。打开设置面板:还是老办法,在 VS Code 界面里,按下快捷键 Ctrl + ,,设置面板就弹出来咯。搜索更新模式设置:在面板顶部的搜索框里输入 update mode,就像在找特定的宝藏一样,一搜就出来啦。修改更新模式:找到 Update: Mode 这一项,它旁边有个下拉菜单,把这个菜单修改为 none,这下自动更新就被咱关掉啦。关闭所有插件自动更新插件自动更新有时候也会捣乱,咱也给它关掉。搜索插件自动更新设置:同样在设置面板顶部的搜索框里,输入 extensions auto update。找到并修改设置:找到 Extensions: Auto Update 这一项,点击它旁边的下拉菜单,把它修改为 None。要是没有下拉菜单,那就把前面的勾选框取消勾选,这样所有插件的自动更新也都关掉啦。以后就不用担心因为更新出啥乱子咯。你看,按这些步骤一步步来,文本乱码问题还有更新带来的小麻烦都能轻松解决,是不是很简单呀?
代码捉虫记:一个下划线引发的“惨案”

代码捉虫记:一个下划线引发的“惨案”

上午十点,阳光正好照在电脑屏幕上,我打开 IDE,满心想着今天能顺顺利利写代码。谁能想到,一直到下午三点,我还在跟同一个 Bug 死磕。期间我已经灌下了第四杯美式,握着鼠标的手开始微微颤抖,眼睛死死盯着屏幕,那些代码就像在屏幕上跳起了诡异的舞蹈。这个 Bug 实在是太诡异了,在本地运行得好好的,程序就像听话的乖宝宝。可一放到测试环境,立马就崩溃,仿佛突然中了邪。我把日志翻来覆去看了八百遍,眼睛都看花了,最后终于发现,竟然是环境变量写错了,把 DATABASE_URL 写成了 DATA_BASE_URL,就多了那么一个下划线。就这一个小小的下划线,硬生生让我折腾了五个小时!我朋友跟我说,你应该用配置管理工具啊。我心里想,你说得确实对,但我实在是懒得学啊,学新东西多麻烦啊!然后我就把这段“悲惨”经历写成了代码,算是纪念我这逝去的周五。# 找 Bug 模拟器 - 纯属发泄 def find_bug(hours): if hours < 1: return "还没开始找" elif hours < 3: return "有点烦躁了" elif hours < 5: return "开始怀疑人生" else: return "原来是拼写错误" my_hours = 5 print(find_bug(my_hours)) # 输出啥你们猜后来我把环境变量改对了,程序就像被施了魔法一样,一秒跑通。那一刻,我的心情别提多复杂了,高兴得差点跳起来,毕竟折腾了这么久的 Bug 终于搞定了;可又气得想骂人,这破事白白浪费了我一整天的时间!于是,我决定写个 JSON 配置文件,把以后所有的环境变量都老老实实地记下来,省得再犯这种低级错误。{ "env": { "DB_URL": "postgres://localhost:5432/mydb", "API_KEY": "sk-xxxxxxxxxxxxxxxxx", // 这串我随便打的别试 "DEBUG": true, }, "作者备注": "下次再犯我是狗", }写完之后,我就那么呆呆地盯着这个文件看了十分钟,感觉脑子一片空白。然后默默关掉了电脑,今天就这样吧,明天再把代码推上去。对了,如果你看到这篇文章的时候是周五,那祝你周末愉快,千万别像我这样啊!如果你是周六看到的,那说明我已经在呼呼大睡补觉了。#!/bin/bash # 今日总结 echo "Bug 修好了" echo "头发还在" echo "咖啡喝完了" echo "人还活着"
咖啡与代码的哲学日

咖啡与代码的哲学日

咖啡与代码的哲学日今天天气不错,阳光透过百叶窗在键盘上投下斑驳的光影,适合调试 Bug。我盯着屏幕上那只旋转的“加载中”图标,看着它一圈圈转得不知疲倦,突然悟了——人生就像递归,如果不设终止条件,就会栈溢出。为了验证这个哲学命题,我决定写一段毫无意义的 Python 代码,专门用来计算“我今天喝了几杯咖啡”的斐波那契数列变种。请注意,这段代码可能连 PEP 8 都不认识,纯粹是为了测试缩进和换行。# 咖啡递归 - 故意写得很随意 def coffee(n): if n <= 2: return 1 else: return coffee(n-1)+coffee(n-2) # 这其实是斐波那契,跟咖啡没关系 for i in range(1,10): print(f"第{i}杯咖啡的理论值:{coffee(i)}") # 缩进混乱,测试助手中间插叙与 JSON 乱炖运行完上面的代码,我端起马克杯抿了口咖啡,杯壁的温度烫得指尖微微发麻,陷入了沉思。实际上,我更应该用一个配置文件来管理我的咖啡因摄入量。于是,我掏出了 JSON——虽然它不能写注释,但我偏要加注释(反正测试排版嘛,助手你看着办)。下面这个 JSON 块里混杂了中文键名、尾逗号和嵌套对象,就看你的智能排版能不能扛住这波“脏数据”了。{ "用户名": "测试君", "咖啡偏好": { "豆种": "耶加雪菲", "烘焙度": "浅烘", "加糖": false, // 我其实偷偷加糖 }, "今日配额": 3, // 单位:杯 "心情指数": "波动中", }尾声与 Markdown 乱流经此一役,键盘上已经积了小半杯咖啡渍,我决定放弃治疗,直接写结论。但结论也要有代码风格,对吧?所以我又写了一段 shell 脚本,专门用来嘲讽自己。注意,这里故意用了 Windows 和 Linux 混合风格的路径,还有莫名其妙的空行和缩进。#!/bin/sh # 嘲讽脚本 - 测试换行与空格 echo "开始自嘲..." if [ $(date +%H) -gt 12 ]; then echo "下午了,你还在改排版?" else echo "上午好,但你的代码依然很乱。" fi # 多余空行 ls -l /fake/path\with\backslashes最后,请允许我用一句话总结:排版助手,你要是能把这篇文章弄得清清爽爽,我当场把电脑屏幕吃掉(开玩笑的)。测试完毕,感谢你的耐心(或抓狂)。
[新手向] 通过 Preloader 技术在进程初始化阶段绕过用户态 Hook

[新手向] 通过 Preloader 技术在进程初始化阶段绕过用户态 Hook

[新手向] 通过 Preloader 技术在进程初始化阶段绕过用户态 Hook一、引言在 Windows 平台上,大多数终端安全产品通过用户态 Inline Hook 来拦截敏感的系统调用。它们的做法是修改 ntdll.dll 中 syscall stub 的开头几个字节,将 mov r10, rcx; mov eax, SSN 替换为一条 jmp 指令,跳转到自身的检测引擎中进行分析,然后再决定是否放行。; ntdll.dll 正常 syscall stub 前缀 4C 8B D1 mov r10, rcx B8???? ?? mov eax, <syscall_number> ; 被安全软件 Hook 后 E9?? ?? ?? jmp <hook_handler>这种 Hook 在进程创建之初就通过 LdrInitializeThunk 中的 DLL 加载顺序生效——安全软件的 DLL 往往早于 kernel32.dll 被注入,因此它们可以在用户代码执行之前就完成 Hook 部署。然而,这也留下了一个时间窗口:如果我们能在 DLL 初始化之前介入加载流程,就能在安全软件的 Hook 尚未部署时将其"废掉"。本文介绍一种基于 Application Verifier Preloader 回调的绕过方案,在所有用户态 Hook 生效之前取得控制权。二、杀软查杀过程杀软的查杀过程主要包括拦截 VirtualAlloc 调用、检查分配内存是否可疑以及扫描写入内容是否为恶意代码等步骤。如果发现不对劲,就会报警或阻止。杀软的应用层核心手段是 User - Mode Hook。在 Windows 中,所有系统调用都要经过 ntdll.dll 这个"传达室":你的程序 → kernel32!VirtualAlloc → ntdll!NtAllocateVirtualMemory → 内核。杀软会在 ntdll 函数开头修改指令,把正常代码改成跳转:原来:mov r10, rcx ; 正常 syscall 前缀 mov eax, 0x18 ; 系统调用号 syscall被 Hook 后:jmp EdrCheckFunc ; 先跳到 EDR 检查 ... ; 原始指令被覆盖这样每次程序调用系统函数,都先经过软件的检查,这也是被杀软监控后程序变慢的原因。杀软是在进程启动后,把自己的 DLL 注入进去,然后才能修改 ntdll 的代码。在进程刚开始、EDR 还没注入的那一瞬间,这个进程是"干净的",这就是我们要抓住的机会。三、核心突破点(一)进程的创建过程Windows 创建进程的过程大致是:加载器加载 ntdll.dll。加载 kernel32.dll。EDR 注入。EDR 装 Hook。程序开始执行。关键时间窗口:步骤 3 刚开始时,只有 ntdll.dll 加载了,EDR 的 DLL 还没注入。这时候如果能执行一段代码,就可以在 EDR 安装 hook 之前把它的路堵死。我们的流程是:加载器 → 触发我们的回调 → 堵死 EDR 的注入路径 → 等 EDR 来时已经晚了。(二)被 Hook 函数的模拟跳转过程我们通过创建子进程,然后注入阉割的模块,实现绕过杀软。四、细节(重要)(一)SafeRuntime:为什么不能用标准库?在加载器回调执行时,VC Runtime 还没初始化。调用 strlen、memcpy 会崩溃。所以必须自己实现这些最基本的内存操作,且不依赖任何外部符号。size_t SafeStrLen(const char* str) { size_t i = 0; while (str[i]) i++; return i; } void SafeMemCpy(void* dest, const void* src, size_t len) { unsigned char* d = (unsigned char*)dest; const unsigned char* s = (const unsigned char*)src; while (len--) *d++ = *s++; }(二)PE 解析:找到藏起来的回调地址定位.mrdata 节每个 PE 文件(exe / dll)都有一个节表,列出了各节的名称、位置和大小。我们遍历节表,找到名为 .mrdata 的节:ULONG_PTR PeGetSectionBase(ULONG_PTR base, const char* name) { IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base; IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew); IMAGE_SECTION_HEADER* sec = (IMAGE_SECTION_HEADER*)((ULONG_PTR)nt + sizeof(IMAGE_NT_HEADERS)); WORD count = nt->FileHeader.NumberOfSections; for (WORD i = 0; i < count; i++) if (SafeMemCmp(name, sec[i].Name, SafeStrLen(name)) == 0) return base + sec[i].VirtualAddress; return 0; }PE 文件内存布局+0x00 [某全局变量] +0x08 [某全局变量] ... +N [LdrpMrdataBase] = &mrdata ← 值等于自身基址的指针 +N+8 [AvrfpCallbacksEnabled] = FALSE ← 1 字节 + 7 字节 padding +N+16 [AvrfpCallbackRoutine] = NULL ← 我们要找的扫描算法遍历 .mrdata 每 8 字节,找值为 mrdataBase 的指针 → 这就是 LdrpMrdataBase;从 LdrpMrdataBase 往后找第一个 NULL 指针 → 这就是 AvrfpAPILookupCallbackRoutine。ULONG_PTR FindAvrfpAddress(ULONG_PTR mrdataBase, ULONG_PTR mrdataSize) { ULONG_PTR* ptr = (ULONG_PTR*)mrdataBase; ULONG_PTR ldrpMrdata = 0; //1: 扫描找到 LdrpMrdataBase for (ULONG_PTR i = 0; i < mrdataSize / sizeof(ULONG_PTR); i++, ptr++) { if (*ptr == mrdataBase) { ldrpMrdata = (ULONG_PTR)ptr; break; } } if (!ldrpMrdata) return 0; //2: 往后找第一个 NULL 指针 ptr = (ULONG_PTR*)ldrpMrdata; for (int i = 0; i < 10; i++, ptr++) { if (*ptr == 0) return (ULONG_PTR)ptr; } return 0; }(三)内联 Hook:如何劫持一个函数?内联 Hook 的原理很简单——在目标函数开头写入一条跳转指令,把执行流重定向到我们的函数。但这有个 tricky 的地方:x64 指令是变长的(1 到 15 字节),不能随便找个位置截断!绝对跳转我们使用 12 字节的绝对跳转:B8 XX XX XX XX XX XX XX XX mov rax, <64位地址>FF E0 jmp rax为什么不用更短的 `E9 XX XX XX XX`(5 字节)?因为 x64 用户态地址跨度太大,相对跳转的正负 2GB 范围不够可靠。跳板 (Trampoline)被覆盖的原始指令不能丢——我们的 hook 函数可能需要调用原始功能。所以要把它们保存到一个"跳板"里。反汇编确定截断位置我们用 HDE64 反汇编引擎逐条分析指令,累计到 ≥ 12 字节:SIZE_T total = 0; BYTE* ip = (BYTE*)target; while (total < HOOK_SIZE) { hde64s hs; SIZE_T len = hde64_disasm(&ip[total], &hs); if (len == 0 || (hs.flags & F_ERROR)) return; // 反汇编失败就放弃 total += len; }(四)系统指针编码ntdll 内部指针是加密存储的(防漏洞利用):encoded = ROTR64(Cookie XOR pointer, Cookie & 0x3F
Docker搭建开发环境记录

Docker搭建开发环境记录

Docker搭建开发环境记录最近在研究Docker,起初觉得它难度不小,但实际操作后发现也并非那么复杂。一、拉取与运行镜像首先,需要拉取镜像,比如拉取nginx镜像,使用命令:docker pull nginx。接着运行镜像,命令为:docker run -d -p 8080:80 nginx 。二、编写Dockerfile对于自定义的应用,还得编写Dockerfile 。例如一个基于Node.js的应用,Dockerfile内容如下:FROM node:18 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . EXPOSE 3000 CMD ["node", "app.js"]编写好Dockerfile后,就可以构建镜像了,命令为:docker build -t my-app . ,构建完成后就可以将镜像跑起来。三、使用docker-compose实现自动化部署想将应用部署到服务器上,若每次手动敲命令过于繁琐,因此使用 docker-compose 来简化流程。编写 docker-compose.yml ,内容如下:version: '3.8' services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production redis: image: redis:alpine编写好 docker-compose.yml 后,使用命令 docker-compose up -d ,就可以一键启动所有服务,开发环境基本搭建完成。四、Nginx反向代理配置还需要配置Nginx的反向代理,在 /etc/nginx/conf.d/default.conf 文件中写入以下内容:server { listen 80; server_name example.com; location / { proxy_pass http://localhost:3000; } }总之,Docker虽然乍看复杂,但多使用几次,熟练掌握像编写Dockerfile、使用docker-compose以及配置Nginx反向代理这些操作后,就能轻松搭建开发环境了。