Chr_小屋 - 调试
type: channel
link: https://blog.chrxw.com/tag/调试
items: 使用C#源生成器自动完成服务注册
items: 【油猴脚本教程】P2 初识油猴脚本 & 油猴脚本的基本构成
items: 【油猴脚本教程】P1 开发者工具的使用 & JavaScript 基础教程
items: 【油猴脚本开发教程】文章索引
items: DirectoryLister 3.5.0 使用教程
items: 安卓逆向入门（一）工具使用与环境配置
items: Python+VSCode开发环境配置指南

使用C#源生成器自动完成服务注册
type: item
date: 2024-01-24T11:28:19+08:00
description: 前言 完整项目地址: https://github.com/chr233/XinjingdailyBot 因为项目之前是使用运行时反射来完成服务的动态注册，而源生成器是在编译前完成代码生成并参与编译，完全没有运行时的性能开销 运行时反射 - 旧的方案 标记特性 首先创建一个 Attribute, 用来标注需要扫描的服务类 namespace XinjingdailyBot.Infrastructure.Attribute; /// /// 标记服务 /// 1、如果服务是本身 直接在类上使用[AppService] /// 2、如果服务是接口 在类上使用 [AppService(ServiceType = typeof(实现接口))] /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class AppServiceAttribute : System.Attribute { /// /// 服务声明周期 /// 不给默认值的话注册的是AddSingleton /// public LifeTime ServiceLifetime { get; set; } = LifeTime.Scoped; /// /// 指定服务类型 /// public Type? ServiceType { get; set; } /// /// 是否可以从第一个接口获取服务类型 /// public bool InterfaceServiceType { get; set; } /// /// 标记服务 /// /// public AppServiceAttribute(LifeTime serviceLifetime) { ServiceLifetime = serviceLifetime; } /// /// 标记服务 /// /// /// public AppServiceAttribute(Type? serviceType, LifeTime serviceLifetime) { ServiceLifetime = serviceLifetime; ServiceType = serviceType; } /// /// 标记服务 /// /// /// /// public AppServiceAttribute(Type? serviceType, LifeTime serviceLifetime, bool interfaceServiceType) { ServiceLifetime = serviceLifetime; ServiceType = serviceType; InterfaceServiceType = interfaceServiceType; } } /// /// 生命周期 /// public enum LifeTime { /// /// 瞬时 /// Transient, /// /// 范围 /// Scoped, /// /// 单例 /// Singleton } 基于反射的服务扫描器 然后再主项目启动的时候使用反射扫描添加了该 Attribute 的所有 Class 并注册服务 using System.Diagnostics.CodeAnalysis; using System.Reflection; using XinjingdailyBot.Infrastructure.Attribute; namespace XinjingdailyBot.WebAPI.Extensions; /// /// 动态注册服务扩展 /// public static class AppServiceExtensions { private static readonly NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger(); /// /// 注册引用程序域中所有有AppService标记的类的服务 /// /// [RequiresUnreferencedCode("不兼容剪裁")] public static void AddAppService(this IServiceCollection services) { var cls = new string[] { "XinjingdailyBot.Repository", "XinjingdailyBot.Service", "XinjingdailyBot.Command", "XinjingdailyBot.WebAPI", }; foreach (var item i…

【油猴脚本教程】P2 初识油猴脚本 & 油猴脚本的基本构成
type: item
date: 2022-08-17T00:00:00+08:00
description: P2 初识油猴脚本 教程索引 视频链接 光讲JS感觉不是特别直观，用两个不涉及网络请求的脚本进行讲解 第一个脚本 - Remove Live.js 脚本链接： https://github.com/chr233/GM_Scripts/blob/master/Bilibili/Remove_Live.js 脚本功能： 提供一个开关，用于移除直播播放器，并且带有记忆功能 源码： // ==UserScript== // @name Remove_Live // @name:zh-CN 去除B站直播间播放器 // @namespace https://blog.chrxw.com // @version 1.1 // @description 去除B站多余的直播播放器（滑稽） // @author Chr_ // @include https://live.bilibili.com/* // @license AGPL-3.0 // @icon https://blog.chrxw.com/favicon.ico // ==/UserScript== (() => { "use strict"; //去除播放器的开关 let VEnable = localStorage.getItem("VEnable") === "true"; if (VEnable) { setTimeout(() => { document.getElementById("live-player").remove(); }, 3000); } let btnArea = document.querySelector(".right-ctnr"); let btn = document.createElement("button"); btn.textContent = VEnable ? "恢复播放器" : "移除播放器"; btn.addEventListener("click", () => { VEnable = !VEnable; localStorage.setItem("VEnable", VEnable); btn.textContent = VEnable ? "恢复播放器" : "移除播放器"; if (VEnable) { document.getElementById("live-player").remove(); } else { location.reload(); } }); btnArea.insertBefore(btn, btnArea.children[0]); })(); 第二个脚本 - SteamDB CN.js 脚本链接： https://github.com/chr233/GM_Scripts/blob/master/SteamDB/SteamDB_CN.js 脚本功能： 汉化SteamDB 源码： // ==UserScript== // @name:zh-CN SteamDB汉化 // @name SteamDB_CN // @namespace https://blog.chrxw.com // @supportURL https://blog.chrxw.com/scripts.html // @contributionURL https://afdian.net/@chr233 // @version 1.32 // @description SteamDB汉化插件 // @description:zh-cn SteamDB汉化插件 // @author Chr_ // @match https://steamdb.info/* // @license AGPL-3.0 // @icon https://blog.chrxw.com/favicon.ico // @resource data https://cf.chrxw.com/SteamDB/SteamDB_CN.json // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_registerMenuCommand // ==/UserScript== (() => { "use strict"; //是否打开调试模式（使用自定义汉化规则而不是在线规则） const DEBUG = localStorage["dbg_mode"] == "开"; //是否在控制台输出未汉化文本 const OUTPUT = localStorage["out_word"] == "开"; GM_registerMenuCommand(`调试汉化文本: 【${DEBUG ? "开" : "关…

【油猴脚本教程】P1 开发者工具的使用 & JavaScript 基础教程
type: item
date: 2022-08-08T23:37:00+08:00
description: P1 开发者工具的使用 与 JavaScript 基础教程 教程索引 视频链接 (上) 视频链接 (下) 开发者工具的使用 F12 或者 菜单 -> 更多工具 -> 开发者工具 调出 切换中文 更改语言后重新打开开发者工具生效 或者 界面简介 元素 HTML 原文 HTML节点的属性 控制台 在任意Tab按ESC可以在下方调出 源代码 浏览网站中的所有资源 调试代码 网络 抓包工具 应用 查看本地储存的内容 Cookie Session LocalStorage JavaScript 基础教程 一些 JavaScript 学习资源 MDN 文档： https://developer.mozilla.org/zh-CN/docs/Web/JavaScript 廖雪峰： https://www.liaoxuefeng.com/wiki/1022910821149312 菜鸟教程： https://www.runoob.com/js/js-tutorial.html uTools 插件 基本特性 单线程 弱类型 / 动态类型 大小写敏感 ' ," 通用 不强制使用分号 (建议统一) 语法很灵活 运行时: v8, NodeJS 基础语法 注释 //单行注释 /* 多行注释 */ 变量与常量 赋值操作符 var let const //定义变量/常量 var a = 1; var b; let c = 1; let d; const e = 4; //a,b,c,d,e 1 undefined 1 undefined 4 console.log("a,b,c,d,e",a,b,c,d,e); //Uncaught SyntaxError: Missing initializer in const declaration const f; //赋新值 a = 2; c = 3; //Uncaught TypeError: Assignment to constant variable. e = 1; //重复定义 //undefined var a = 6; let c = 6; //Uncaught SyntaxError: Identifier 'a' has already been declared let a = 6; //Uncaught SyntaxError: Identifier 'a' has already been declared const a = 6; //常量覆盖 const e = 6; //e 6 console.log("e",e); //在子域中覆盖(ES6引入) var ts = 1; let he = 2; { var ts = "aaa"; let he = "yyy"; //ts,he aaa yyy console.log("ts,he",ts,he); } //ts,he aaa 2 console.log("ts,he",ts,he); var 定义一个 变量 let 定义一个仅在作用域内生效的 变量 const 定义一个 常量，一旦定义无法修改，但是可以覆盖定义 使用相同的操作符可以覆盖定义同名的变量，但是不建议这么使用 使用 let 覆盖定义时不影响父作用域的同名变量 强烈推荐优先使用 let 定义变量，如果值不需要改变，建议使用 const 定义成常量 函数提升 //函数提升 foo(); // "bar" function foo() { console.log("bar"); } //这种写法的函数不会被提升 bar(); // 类型错误：bar 不是一个函数 var bar = function() { console.log("bar2"); }; 作用域 { } 定义代码作用域 (ES6的内容) 使用 let 定义的变量，在子域可以访问父域的变量，但是父域不能访问子域的变量 函数中定义的内容外部无法访问 子域中定义的函数，父域无法访问 //顶级作用域(最外层的作用域) let x = 114; { //子作用域 let b = 514; //x,b 114 514 console.log("x,b", x, b); } //函数内部其实也是一种作用域 function xbz() { let c = 233; //x,c 114 233 console.log("x,c", x, c); //Uncaught ReferenceError: b is not defined console.log("b", b); } xbz(); //匿名函数同理 (() => { let d = 3.14; //x,d 114 3.14 console.log("x,d", x, …

【油猴脚本开发教程】文章索引
type: item
date: 2021-10-19T18:24:00+08:00
description: 前言 之前写过一篇教程，那个时候经验有限，很多地方讲的不是很明白 所以这是一篇重制版教程 计划每周一更，每次30min左右，大纲讲完以后会讲解一些例程 教程大纲 大概会涉及到的内容，顺序未定 开发环境配置（P0 文章 视频） VS Code Git 使用基础 远程 Git 仓库 脚本分发（P0 文章 视频） Greasyfork 使用 使用 WebHook 自动更新 开发者工具简介（P1 文章 视频） 元素 控制台 源代码 网络 应用 JavaScript基础 （P1 文章 视频） 变量与常量 作用域 数据类型与类型转换 执行流 Window 对象 Document 对象 Node 对象 Element 对象 初识油猴脚本 (P2 文章 视频) 两个简单的脚本源码解析 油猴脚本组成 (P2 文章 视频) 元信息 脚本 DOM 元素操作 数据持久化 localStorage 自定义 CSS 油猴脚本组成 元信息 脚本 库 CSS选择器与XPath语法基础 DOM元素操作 Event事件 数据持久化 序列化与反序列化 自定义CSS 库的使用与开发 正则表达式基础 同步函数与异步函数和并发 网络请求（XHR/Fetch） 油猴API 开发实战…… 联系方式 有任何问题直接留言或者私信即可 博客留言（Chrxw.com） B站私信 （Chr_@5805394） 电子邮件（chr@chrxw.com）

DirectoryLister 3.5.0 使用教程
type: item
date: 2020-09-21T20:15:00+08:00
description: 前言 DirectoryLister是一款非常小巧的PHP文件浏览器，适合搭建一个简单的个人文件站，之前的教程使用的版本为2.7.1，现在的最新版本为3.5.0，新增了文件夹说明、文件搜索等功能。 我的示例站点：链接 安装步骤 环境需求 PHP版本为 7.2 及以上 安装PHP的 zip、DOM、Fileinfo 扩展，前两个宝塔面板自带，只需安装Fileinfo 下载源码 官方网站 GitHub 本地镜像 @> 本站只提供3.5.0版本下载，最新版本请从官方渠道下载 安装 下载好以后，解压到网站根目录，将 .env.example 文件重命名为 .env 文件，然后用编辑器打开 @> Windows下如果无法重命名的话，可以使用命令 rename .env.example .env !> 如果修改了 .env 文件但是配置不生效，解禁PHP的 putenv 函数即可 .env 配置文件说明 # 调试模式开关 APP_DEBUG=false # 语言设置(zh-CN即简体中文) APP_LANGUAGE=zh-CN # # 深色模式开关(蓝白/紫黑) DARK_MODE=false # 是否在文件列表下方显示Readme.md文件(如果存在Readme.md文件) DISPLAY_READMES=true # 在文件列表上方显示Readme.md文件(需要DISPLAY_READMES=true) READMES_FIRST=false # 是否允许将整个目录打包成ZIP下载(搜索栏左侧会显示打包下载按钮) ZIP_DOWNLOADS=true # # Google Analyitcs设置(要使用的话设置成资源ID即可) GOOGLE_ANALYTICS_ID=false # GOOGLE_ANALYTICS_ID=UA-XXXXXXXXX-X # # MATOMO_ANALYTICS设置 MATOMO_ANALYTICS_URL=false MATOMO_ANALYTICS_ID=false # # 排序设置，可选值如下，排序方式区别见下 # type, natural, name, accessed, changed, modified SORT_ORDER=type # 逆序排序开关 REVERSE_SORT=false # # 隐藏app目录 HIDE_APP_FILES=true # 隐藏.git目录 HIDE_VCS_FILES=true # # 时间格式 DATE_FORMAT="Y-m-d H:i:s" # 时区设置（Asia/Shanghai即上海时间） TIMEZONE="Asia/Shanghai" # # 可以计算Hash的文件的最大尺寸(单位是字节Bytes) MAX_HASH_SIZE=1000000000 # # 主页标题，显示在网页左上角(默认为“目录起始页”) HOME_TEXT="文件下载" # 页面缓存设置，设为false禁用缓存(默认值为"app/cache/views") VIEW_CACHE="app/cache/views" 如果能正确显示网页，说明安装成功了: 定制 i> 修改后需要清除页面缓存后才能看到效果，默认缓存目录为 app/cache/ ，删掉整个目录即可 网站标题优化 将 Home 修改成中文 文件路径为 app\src\Controllers\DirectoryController.php 改成想要的值，比如“主页” 定制标题格式 文件位置在 app\views\layouts\app.twig {{ title }} 是占位符，用来显示当前目录的名称，其他的文本都可以任意改，如果使用特殊符号记得转义 常用符号转义值：" ",& &,< <,> > EXE图标显示空白解决方法 打开app\config\icons.php 把所有 fas fa window 替换成 fab fa windows 即可 @> 原因是新版的 Font Awesome 貌似需要Pro才有这个图标…… 中文字体优化 修改版 app.css 下载: 链接 文件路径为 app\assets\app.css 隐藏特定的文件 在网站根目录下新建一个 .hidden 文本文件，在里面写入希望隐藏的文件名或者路径名即可，支持正则表达式 页面自定义 页眉模板文件：app/views/components/header.twig 页脚模板文件：app/views/components/footer.twig CSS文件：app/assets/app.css 本地化文件：app/translations/zh-CN.yaml

安卓逆向入门（一）工具使用与环境配置
type: item
date: 2020-07-27T18:39:00+08:00
description: 环境配置 ROOT真机或者带完整ROOT的模拟器 IDE，推荐使用VS Code或者Android Studio JAVA环境（各种工具需要使用到） ADB（建议加到PATH中） 常用工具介绍 @> 基本都可以在52破解的网盘里找到：链接 Jadx 功能比较简单，速度比较快，反编译和反混淆的结果比JEB容易看一点。 只支持smali，不支持JNI，也就是Native层的反编译。 JEB 相比Jadx功能更多，支持反编译JNI。支持动态调试，支持脚本和插件。 IDA 跨平台的反编译工具，反编译JNI比较好用。支持动态调试，支持脚本和插件。 ADM (Android Device Monitor) ADM是安卓SDK中附带的实用工具，路径为\android-sdk\tools\lib\monitor-x86_64\monitor.exe。 动态调试方法 开启调试模式 i> 如果出现了debug标志代表该设备开启了调试模式，可以跳过本节 确保设备已经刷入Magisk并激活 安装Busybox for Android NDK和MagiskHide Props Config模块，重启后生效。 使用ADB Shell或者Termux等软件，运行命令： su props 依次选择Edit MagiskHide props -> ro.debuggable，然后输入y修改值，最后输入y，重启系统后生效。 @> 系统有可能会重启2次，是正常现象。 验证是否成功 如果在ADM中可以看到debug标志说明修改成了。 使用ADB启动调试会话 查看应用包名和启动入口 构造ADB调试命令 adb shell am start -D -n [包名]/[启动Activity名] 例如上面的例子，构造以后是这样的： adb shell am start -D -n com.example.easyre/com.example.easyre.MainActivity 等待附加调试器 如果命令正确，将会弹出等待调试的提示： ADM的设备列表中也会在对应进程前面显示一个调试图标： 使用 JEB 进行附加调试 确保已经使用'ADB'连接到了设备 使用JEB打开APK，并在手机或者模拟器上运行对应应用。 在JEB中启动附加调试 下断点方法 在Java视图定位到代码以后，按TAB切换到Smali视图，使用调试器->打开或关闭断点添加或者移除断点。 使用 IDA 进行动态调试 部署IDA调试工具 默认路径在dbgsrv下，android_server和android_server64适用于ARM架构32位和64位应用，android_x86_server和android_x64_server适用于x86架构32位和64位应用，如果都不能正常工作，可以试试android_server_nonpie。 使用ADB传到安卓系统中adb push [本地文件路径] [远程文件路径]，例如： adb push Desktop\IDA\dbgsrv\android_server /data/ida_server adb push Desktop\IDA\dbgsrv\android_server64 /data/ida_server64 修改文件权限，可以使用adb shell或者Termux： cd /data chmod 755 ida_server* 启动调试工具 ./android_server & @> 加 & 可以让进程在后台运行。 在IDA中启动附加调试 使用 Android Studio 进行动态调试 使用Apktool生成逆向后的工程文件 apktool d [APK路径] i> 如果Apktool反编译失败，可以试试Jadx 在 Android Studio 中打开APK文件 导入安卓工程 创建调试配置 在Android Studio中启动调试会话

Python+VSCode开发环境配置指南
type: item
date: 2020-07-12T12:26:00+08:00
description: Python安装 前往Python官网下载最新的版本链接 我写这篇文章的时候最新版本为3.8.3，点进去然后拉到最下面 下载64位或者32位安装包，如果官网下载太慢，也可以试试本地镜像(64位) 下载好后运行安装程序，勾选Add Python 3.8 to PATH 安装结束后，点击Disable path length limit，然后关闭安装程序 按快捷键Win + R，然后输入Python，如果看到图中的黑框框，说明安装完成了。 接下来设置Python包管理器pip 使用管理员权限运行CMD，然后粘贴下面的命令 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple 命令的作用是把pip的安装源改成清华的镜像，可以大大加快Python模块的安装 VScode安装 前往Visual Studio Code官网下载最新的版本链接 下载64位或者32位安装包，然后运行安装程序 推荐勾选这几个选项，其他保持默认即可 安装完成 运行VSCode看到图中的窗口就说明安装完成了，不过VSCode默认没有简中语言包，可以手动安装汉化包。 VSCode 配置 安装中文语言包 先在左侧栏选择Extensions(插件)，然后在搜索框输入chinese，最后在中文语言包右下角点install 稍等片刻，当出现如图提示的时候，点Restart Now，等待VSCode重启完成，就变成中文界面了 安装Python插件 跟上一步差不多的步骤，在插件栏搜索Python 如果VSCode没有正确识别，就需要手动设置Python的位置 其他插件 推荐安装Visual Studio IntelliCode插件，微软出品的代码补全插件 VSCode 入门指南 第一个项目 VSCode是以文件夹为单位区分不同项目的，所以要创建新项目只需要建立一个文件夹，然后在VSCode中打开该文件夹即可 打开文件夹以后VSCode底栏颜色会从紫色变成蓝色 如果出现图中的错误提示，点Install即可 等待它完成安装出现如图提示即可 新建helloworld.py 输入代码：print('Hello World') 配置启动方式 选择创建launch.json 保存即可生效，左侧也会显示调试工具 回到helloworld.py，按F5即可启动调试会话 在调试模式中底栏会变成橙色 可以看到，已经输出了Hello World