浅谈nim加载.NET程序集

admin 2024年2月4日14:14:32评论11 views字数 5962阅读19分52秒阅读模式

关注并星标🌟 一起学安全❤️

作者:coleak  

首发于公号:渗透测试安全攻防 

字数:12280

声明:仅供学习参考,请勿用作违法用途

目录

  • 前记

  • nim攻防基础

    • FFI

    • 内存加载

    • 加解密、编码

  • 后记

    • C#类型转换表

    • nim基础

前记

随便编写一个c#调用winapi并用vs生成dll,同时用csc生成exe

using System;
using System.Runtime.InteropServices;
namespace coleak
{
    class winfun
    {
        [DllImport("User32.dll")]
        public static extern int MessageBox(IntPtr h, string m, string c, uint type);
        [DllImport("kernel32.dll", EntryPoint = "Beep")]
        public static extern bool mymethod(uint frequency, uint duration);
    }
        class Program
    {
            static void Main(string[] args)
            {
            winfun winfun = new winfun();
            winfun.MessageBox((IntPtr)0"yueyy""coleak",(uint0);
            Random random = new Random();
            for (int i = 0; i < 10000; i++)
            {
                winfun.mymethod((uint)random.Next(10000), 100);
            }
            Console.ReadLine();
            }
    }
}
/*BOOL Beep(
DWORD dwFreq,
DWORD dwDuration
);
int MessageBox(
  [in, optional] HWND hWnd,
  [in, optional] LPCTSTR lpText,
  [in, optional] LPCTSTR lpCaption,
  [in] UINT uType
);*/

优点:隐藏导入表,仅存在mscoree.dll

缺点:在dnspy下均直接出源码

nim攻防基础

为了更加OPSEC,考虑使用nim代替c#核心部分,nim防止反编译同时也不暴露导入函数

FFI

proc MessageBoxA*(hWnd: int, lpText: cstring, 
lpCaption: cstring, uType: int32): int32
{.discardable, dynlib: "user32", importc.}
MessageBoxA(0, "Hello, world !", "MessageBox Example", 0)

proc WinExec*(lpCmdLine:cstring,uCmdShow:int32): int32 {.discardable,dynlib:"kernel32",importc.}
WinExec("calc.exe",0)

proc printf(format: cstring): cint {.importc, varargs,discardable.}#discardable忽略返回值否则报错
printf("My name is %s and I am %d years old!n", "coleak", 20)

proc mycmp(a, b: cstring): cint {.importc: "strcmp", nodecl.} #=proc strcmp(a, b: cstring): cint {.importc, nodecl.}
let cmp = strcmp("Easy!", "Easy!")
echo cmp

嵌入c

when not defined(c):
{.error: "Must be compiled in c mode"}
{.emit: """
#include <stdio.h>
int Test()
{
char name[100]={0};
scanf("%s",name);
printf("嵌入成功,%s",name);
return 0;
} // end main
""".}

proc Test(): int
{.importc: "Test", nodecl,discardable.}
when isMainModule:
discard Test()

内存加载

读取字节流

import os
var buf: array[4096,byte]
var f: File
f = open(r"D:c_projectnimtest.exe")
discard readBytes(f, buf,0,4096)
f.close()
echo buf

c.exe>aaa.txt

import winim/clr
import sugar
import os
var buf: array[4096,byte]
buf = [77, 90, ..., 0]
var assembly = load(buf)
var arr = toCLRVariant(commandLineParams(), VT_BSTR)
assembly.EntryPoint.Invoke(nil, toCLRVariant([arr]))

c#虽然没有暴露导入信息,但是在hxd下会暴露字符串信息,因此在 Nim 编译的可执行文件中检测 .NET 程序集仍然很容易,还可以用hxd轻松搜到nim加载的程序集中存在的user32.dll字符信息和exe关键词

浅谈nim加载.NET程序集

加解密、编码

base64

import base64
import os
import strformat
func toByteSeq*(str: string): seq[byte] {.inline.} =
# Converts a string to the corresponding byte sequence
@(str.toOpenArrayByte(0, str.high))
let inFile: string = paramStr(1)
let inFileContents: string = readFile(inFile)
# To load this .NET assembly we need a byte array or sequence
var bytesequence: seq[byte] = toByteSeq(inFileContents)
let encoded = encode(bytesequence)
echo fmt"[*] Encoded: {encoded}"
import base64
import os
import strformat
import winim/clr
import sugar
import os
func toByteSeq*(str: string): seq[byte] {.inline.} =
# Converts a string to the corresponding byte sequence
@(str.toOpenArrayByte(0, str.high))
let encoded = r"TVqQAAMAAAAEAAAA//8...AAA=="
let decoded = decode(encoded)
let mys=toByteSeq(decoded)
var assembly = load(mys)
var arr = toCLRVariant(commandLineParams(), VT_BSTR)
assembly.EntryPoint.Invoke(nil, toCLRVariant([arr]))

可以换成别的方式加密.NET 程序集,用于运行时解密

后记

C#类型转换表

Windows C#
BOOL int
BOOLEAN byte
BYTE byte
UCHAR byte
UINT8 byte
CCHAR byte
CHAR sbyte
CHAR sbyte
INT8 sbyte
CSHORT short
INT16 short
SHORT short
ATOM ushort
UINT16 ushort
USHORT ushort
WORD ushort
INT int
INT32 int
LONG int
LONG32 int
CLONG uint
DWORD uint
DWORD32 uint
UINT uint
UINT32 uint
ULONG uint
ULONG32 uint
INT64 long
LARGE_INTEGER long
LONG64 long
LONGLONG long
QWORD long
DWORD64 ulong
UINT64 ulong
ULONG64 ulong
ULONGLONG ulong
ULARGE_INTEGER ulong
HRESULT int
NTSTATUS int

nim基础

语法速记

一、分支允许使用逗号分隔的值列表

let name = readLine(stdin)
case name
of "":
echo "Poor soul, you lost your name?"
of "name":
echo "Very funny, your name is name."
of "Dave", "Frank":
echo "Cool name!"
else:
echo "Hi, ", name, "!"

二、of全覆盖

from strutils import parseInt
echo "A number please: "
let n = parseInt(readLine(stdin))
case n
of 0..2, 4..7: echo "The number is in the set: {0, 1, 2, 4, 5, 6, 7}"
of 3, 8: echo "The number is 3 or 8"
else: discard

三、迭代器

echo "Counting down from 10 to 1: "
for i in countup(1, 5):
echo i
for i in countdown(6, 2):
echo i
for i in 10..19:
echo i
for i in 1..<19:
echo i

四、块语句

block myblock:
echo "entering block"
while true:
echo "looping"
break # 跳出循环,但不跳出块
echo "still in block"

block myblock2:
echo "entering block"
while true:
echo "looping"
break myblock2 # 跳出块 (和循环)
echo "still in block"

五、缩进原则

# 单个赋值语句不需要缩进:
if x: x = false

# 嵌套if语句需要缩进:
if x:
if y:
y = false
else:
y = true

# 需要缩进, 因为条件后有两个语句:
if x:
x = false
y = false

六、函数

proc yes(question: string): bool =
echo question, " (y/n)"
while true:
case readLine(stdin)
of "y", "Y", "yes", "Yes": return true
of "n", "N", "no", "No": return false
else: echo "Please be clear: yes or no"

if yes("Should I delete all your important files?"):
echo "I'm sorry , I'm afraid I can't do that."
else:
echo "I think you know what the problem is just as well as I do."

proc add(a:int,b:int):int=
return a+b

echo add(1,89)

proc sumTillNegative(x: varargs[int]): int =
for i in x:
if i < 0:
return
result = result + i

echo sumTillNegative() # echos 0
echo sumTillNegative(3, 4, 5) # echos 12

函数定义格式看起来很繁琐,返回值类型放在: bool =

result 总在过程的结尾自动返回如果退出时没有 return语句

七、传实参

proc divmod(a, b: int; res: var int,remainder:var int) =
res = a div b # 整除
remainder = a mod b # 整数取模操作

var x, y=111

divmod(8, 5, x, y) # 修改x和y
echo x
echo y

传递实参用var修饰

八、忽略返回值discard

proc p(x, y: int): int {.discardable.} =
return x + y

var c:int
c=p(3, 4) # now valid
echo c
p(3, 4)

九、数组初始化

type
IntArray = array[0..7, int] # 一个索引为0..7的数组
QuickArray = array[6, int] # 一个索引为0..5的数组
var
x: IntArray
x = [1, 5, 3, 4, 5, 77,9,8]
for i in low(x)..high(x):
echo x[i]
for i in x:
echo i

for i, v in @[3, 7, 5]:
echo "index: ", $i, ", value:", $v
# --> index: 0, value:3
# --> index: 1, value:4
# --> index: 2, value:5

十、结构体

type
Person = object
name: string
age: int

var person1 = Person(name: "Peter", age: 30)

echo person1.name # "Peter"
echo person1.age # 30

var person2 = person1 # 复制person 1

十一、读写文件

#字节流
import os
var buf: array[100,byte]
var f: File
f = open("D:\c_project\nim\d.exe")
discard readBytes(f, buf,0,9)
f.close()
echo buf


#文本文件
var file:File
file = open(r"D:c_projectnimd.txt")
echo file.readAll()
file.close()

let text = "Cats are very cool!"
writeFile("cats.txt", text)

十二、绝对路径默认目录为shell路径

文章首发于:渗透测试安全攻防

原文始发于微信公众号(渗透测试安全攻防):浅谈nim加载.NET程序集

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月4日14:14:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅谈nim加载.NET程序集https://cn-sec.com/archives/2464411.html

发表评论

匿名网友 填写信息