b1n.io

19yo, a cyber security researcher.

Antivirus User Mode Hook Nowadays

杀软用户模式HOOK(UMH)现状 关于前文R0 Anti Antivirus的一些更详尽的补充内容, 请先看前文 UMH介绍 UMH一般是使用DLL注入技术, 前文提到杀软可以利用Kernel Callback接收到进程创建回调, 如此杀软不必定时刷新进程列表进行注入, 而是可以实时响应. 在实际中杀软并不会对每个程序都进行注入, 有一些判定规则, 比如是否有证书签名等, 各家杀软判断规则不尽相同, 但是证书都是一个重要的参考 UMH检测 关于UMH的检测, 我在实际中测试某不知名杀软时, 发现一个有趣的事情, 使用VS直接进行调试的时候, 杀软无法成功注入DLL, 猜测是VS已经附加了调试器, 其他进程便无法再打开句柄. UMH一般是直接使用JMP指令, 也就是把将API函数入口修改成JMP到杀软自己的DLL中的函数, 然后杀软可以对参数内容进行检测和处理. 代码实现就是获取API函数地址, 然后反汇编该地址查看是否指令是JMP. 想要了解更多: https://www.ired.team/offensive-security/code-injection-process-injection/how-to-hook-windows-api-using-c++ 我这里使用github开源项目进行UMH的检测: https://github.com/Mr-Un1k0d3r/EDRs/blob/main/hook_finder64.exe?raw=true 使用方式如下: hook_finder64.exe C:\windows\system32\ntdll.dll 可以看到, 杀软HOOK了许多API函数, 我这里测试的杀软叫做Vipre UMH现状 为什么这里没有使用卡巴斯基作为演示呢? 因为现在UMH已经被主流杀软抛弃了, 包括卡巴斯基, 360, 火绒, 原因当然很简单, 因为太容易绕过了, 而且有更强大的Kernel Callback 前文验证 之前提到UMH依赖Kernel Callback进行实时响应, 但是没有给出验证过程, 接下来我们一起来验证一下. 既然UMH依赖Kernel Callback, 那么我们把Kernel Callback干掉, UMH也应该失效. 由于Vipre不会注入有签名的程序, 所以我们需要自己写个程序, 观察注入情况. 代码很简单: #include <iostream> int main() { system("pause"); return 0; } 中间让程序停住, 方便我们观察差异....

April 21, 2023 · b1n

R0 Anti Antivirus

R0 杀软对抗 由于臭名昭著的Patch Gaurd(PG), 安全软件厂商从长远考虑, 只得使用其他途径实现系统监控, 我将介绍现代杀软的实现原理和技术结构. 技术结构 WIndows并不想将系统权限交出去, 而Linux则相反, 有了root权限, 可以做任何事. 所以Linux rootkit非常昌盛, 不过Windows相比并无太多优势. 为了维持系统稳定和反rootkit, 微软做了很多事情, 包括Patch gaurd, 也包括证书签名要求, 但是这样也限制了安全软件的手脚, 安全软件只能使用Windows提供的通知, 或者事件等进行系统监控, 病毒检测. 核心技术就三种, 掌握这三种技术, 无视杀软就是了. 在R0, 杀软使用Minifilter驱动技术, 监控磁盘文件更改, 在R3发起FS请求后, 由IO管理器(I/O Manager)将请求转发到过滤管理器(Filter Manager), 过滤管理器将把请求发送到Minifilter驱动, 此时杀软可对文件进行检测. 杀软检测到文件改动后, 会对文件进行检测, 这就是静态查杀. 这就是为什么把mimikatz放到杀软环境中, 总是看不到猕猴桃图标就被杀了, 因为文件还未真正写入磁盘, 还在某个缓冲区中, 就被检测随即阻止写入. 这是杀软重要的一环 杀软还会利用Kernel Callback, MSDN称其为Callback Objects. 杀软一般会订阅CreateProcess, CreateThread, LoadImage, Registry等等回调, 以实现对进程和注册表的监控. 杀软收到CreateProcess的回调后, 会将自身DLL注入, 以实现R3 HOOK, 进行更详细的分析. 这一步R0和R3的配合就叫做动态查杀. 我还发现, 现在的主流杀软, 比如卡巴斯基, 基本不依靠ETW进行监控, 因为ETW也靠Kernel Callback进行系统监控, 但是ETW可被轻松绕过, R3和R3属于公平竞争, 详细文章参见@bats3c的博客: https://blog.dylan.codes/pwning-windows-event-logging...

April 19, 2023 · b1n

Orust Mimikatz Bypass Kaspersky

混淆版rust mimikatz bypass卡巴斯基 rust = rust + LLVM orust = rust + OLLVM rust后端使用LLVM, 所以可以使用OLLVM做混淆, 我之前在思考怎样把OLLVM用到rust上, 前几天看到已经有相关文章了, 感谢@ny0c 不过文章中有几处地方可能是作者故意留坑, 我将告知大家正确的流程: 编译LLVM 编译LLVM时, 不要编译动态库, 编译动态库后生成的lib文件后缀将是.dll.a, 导致后续编译rust时缺少库文件, 正确的编译命令如下 cmake -G "Ninja" -S ./llvm-project/llvm -B ./build_dyn_x64 -DCMAKE_INSTALL_PREFIX=./llvm_x64 -DCMAKE_CXX_STANDARD=17 -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lld;" -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_INSTALL_UTILS=ON -DLLVM_INCLUDE_TESTS=OFF -DLLVM_BUILD_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_BUILD_BENCHMARKS=OFF 这样编译后也无需修改src/bootstrap/compile.rs 自定义toolchain 自定义toolchain时有一些细节没提到, 编译出来的stage1-tools-bin文件夹中cargo.exe, 要放到stage1/bin目录下, 其他文件放到stage1/libexec目录下, 这样才是一个比较完整的toolchain 还有一些细节我想提出来: 打包toolchain的细节 编译好了toolchain, 怎么打包存放或者分发呢? 先按照上面将完整toolchain配置好, 然后复制stage1文件夹出去, 然后删除rust文件夹下的build目录, 再删除stage1/lib/rustlib/src/rust文件, 这个文件是个链接, 随后复制整个rust文件夹到stage1/lib/rustlib/src. 因为stage1目录下引用了rust目录, rust目录下又存在stage1目录, 导致循环引用, 我在使用WinRAR时是无法打包的 编译的库路径问题 大家都知道, rust默认编译后会将一些敏感目录打包进二进制文件, rust的库也存在类似的问题. 一般的解决方案是使用--remap-path-prefix去映射, 但是在编译rust的本身的库的时候, 是无法完全控制的, 为什么说无法完全控制呢?...

April 16, 2023 · b1n

Customized Network Layer Protocol C2

0x9bc2 Raw Socket留下的坑, 自定义网络层协议实现木马通信 实现细节 server和agent都需要高权限运行, 因为使用了原始套接字(raw socket) server使用原始套接字监听监听0x9bIP协议号 agent发送协议号为0x9b的原始IP数据包 我们将使用socket2和etherparsecrate实现核心功能 server核心代码 // 创建0x9b协议号的原始套接字 let sock = Socket::new(Domain::IPV4, Type::RAW, Some(Protocol::from(155)))?; // 创建堆区缓冲区 let mut data = Box::new([MaybeUninit::new(0u8); 65535]); // 接收数据, 并得到agent的SockAddr结构 let (n, agent) = sock.recv_from(&mut *data)?; // 切片数据 let data = &self[..n]; // 创建迭代器, 过滤出所有有效数据, 并收集成Vec<u8> let data: Vec<u8> = data .iter() .filter_map(|r| Some(unsafe { r.assume_init() })) .collect(); // 提取出IPv4协议下的数据 let (_, data) = Ipv4Header::from_slice(data.as_slice())?; agent核心代码 // 创建stdlib net下的SocketAddrV4, 指向服务器IP let server = SocketAddrV4::new("127....

April 1, 2023 · b1n

Aya Basic Tutorial

aya1基础教程 开发环境 安装rust, 并使用nightly版本(nightly版本可选) curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup default nightly 在linux x86_64上安装bpf-linker cargo install bpf-linker 如果是其他架构的linux或者macos则需要先安装LLVM15, 然后安装连接器 cargo install --no-default-features --features system-llvm bpf-linker 安装cargo-generate用于生成项目模板 cargo install cargo-generate 安装bpftool用于生成BTF Ubuntu发行版(推荐Ubuntu 20.04 LTS (Focal))使用以下命令安装 sudo apt install linux-tools-$(uname -r) export PATH=/usr/lib/linux-tools/$(uname -r):$PATH 创建项目 使用cargo-generate创建新项目 cargo generate https://github.com/aya-rs/aya-template 输入项目名: do-sys-open 选择eBPF程序类型: kprobe 输入挂载点: do_sys_open 框架分析 创建的新项目应该有以下结构 $ ls Cargo.lock Cargo.toml do-sys-open do-sys-open-common do-sys-open-ebpf README.md xtask do-sys-open: 与项目名同名的是用户态程序, 用于加载eBPF程序...

March 25, 2023 · b1n