Chr_小屋 - void
type: channel
link: https://blog.chrxw.com/tag/void/
items: 使用C#源生成器自动完成服务注册
items: 小黑盒逆向分析笔记（五）【未完成】
items: 小黑盒逆向分析笔记（二）

使用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…

小黑盒逆向分析笔记（五）【未完成】
type: item
date: 2021-11-19T13:28:00+08:00
description: 前言 本文仅供学习探讨之用，如果侵犯您的权益请联系我删除。 上文 [post cid="714"/] [post cid="1347"/] [post cid="1365"/] [post cid="1383"/] 前情提要 距离上一篇文章已经过去一年多了，前两天心血来潮找了最新版本研究了一下，熬了两天夜也没整明白，不打算继续研究下去了，做个笔记记录下分析过程。 @> 本文适用于小黑盒 1.3.191，小黑盒历史版本参考我的仓库 @> 全文评论后可见

小黑盒逆向分析笔记（二）
type: item
date: 2020-08-05T22:30:00+08:00
description: 前言 本文仅供学习探讨之用，如果侵犯您的权益请联系我删除。 上文 [post cid="714"/] 距离上一篇文章已经过了半年了，最近也是刚好在学逆向相关的内容，就拿以前的工程来练手。 静态分析 还是接着上文，寻找hkey计算方式 可以看到，生成hkey的过程中调用了Native函数encode，这个函数在libnative-lib.so里 解压出so文件，拖进IDA，可以看到伪代码，可以看到一共有5个参数，但是在Java代码中是3个参数，前2个参数是不需要的。 尝试直接Hook，但是只能得到看不懂的结果，应该都是字符串地址。 我们换个思路，从return开始分析 int __fastcall encode(int a1, int a2, int a3, int a4, int a5) { const char *v5; // r10 int v6; // r4 int v7; // r6 int v8; // r8 const char *v9; // r11 int v10; // r0 bool v11; // zf size_t v12; // r5 char *v13; // r5 char *v14; // r0 size_t v15; // r0 char *v16; // r0 int v17; // r5 int result; // r0 int v19; // [sp+0h] [bp-30h] int *v20; // [sp+4h] [bp-2Ch] int v21; // [sp+8h] [bp-28h] int v22; // [sp+Ch] [bp-24h] v19 = a4; v6 = a1; // v6 是第一个参数 v7 = a4; if ( j_check_signature(a1) == 1 ) // 看名字应该是验证签名的方法 { v8 = 0; v9 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v6 + 676))(v6, v7, 0); v10 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v6 + 676))(v6, a5, 0); v11 = v9 == 0; if ( v9 ) { v5 = (const char *)v10; v11 = v10 == 0; } if ( !v11 ) { v21 = a5; v12 = strlen(v9); v20 = &v19; v13 = (char *)&v19 - ((strlen(v5) + v12 + 21) & 0xFFFFFFF8); v14 = strcpy(v13, v9); v15 = strlen(v14); _aeabi_memcpy(&v13[v15], "/bfhdkud_time=", 15); v16 = strcat(v13, v5); v17 = j_MDString(v16); // v16 被赋值 (*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v6 + 680))(v6, v7, v9); (*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v6 + 680))(v6, v21, v5); v8 = j_charToJstring(v6, v17); // v8 被赋值，值与v6，v17有关 } if ( _stack_chk_guard == v22 ) return v8; // 返回值是 v8 } //正常逻辑应该走不到这里 result = _stack_chk_guard - v22; if ( _stack_chk_guard == v22 ) result = j_j_charToJstring(v6, UNSIGNATURE[0]); return result; } 不难看出，返回值跟j_charToJstring和j_MDString有关，j_大概是一个修饰符，真实函数应该是charToJstring和MDString 找到目标，接下来上Hook。 动态分析 接下来使用 Frida 进行分析，Frida 安装与使用可以参考： [post cid="1301"/] Python 加载器 保存为run.py import sys import frida process_name = 'com.max.xiaoheihe' # 发送信息回调函数 def on_message(mess…