Skip to content

Commit 4e12e2e

Browse files
committed
Clean up, use a config file to avoid hardcoding paths
1 parent 50983de commit 4e12e2e

9 files changed

+624
-112
lines changed

antivirus_debugger.py

+20-17
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
1-
import logging
2-
import os
3-
import sys
4-
import random
5-
import base64
6-
import r2pipe
7-
import string
8-
import shutil
91
import argparse
2+
import sys
3+
from tempfile import NamedTemporaryFile
104

11-
from copy import deepcopy
12-
from dataclasses import dataclass
13-
from scanner import DockerWindowsDefender, VMWareDeepInstinct, VMWareKaspersky, VMWareAvast
145
from find import bytes_detection
156
from find_bad_strings import bissect
167
from pe_utils import *
17-
from tempfile import NamedTemporaryFile
8+
from scanner import DockerWindowsDefender
9+
from scanner import g_scanner
1810

1911
log_format = '[%(levelname)-8s][%(asctime)s][%(filename)s:%(lineno)3d] %(funcName)s() :: %(message)s'
2012
logging.basicConfig(filename='debug.log',
@@ -32,7 +24,6 @@
3224
consoleHandler.setFormatter(logFormatter)
3325
rootLogger.addHandler(consoleHandler)
3426

35-
g_scanner = None
3627
BINARY = ""
3728

3829
g_args = None
@@ -136,7 +127,7 @@ def strings_analysis(pe):
136127
if detection_result:
137128
logging.info(f"{g_scanner.scanner_name} seems to only detect strings in this binary.")
138129
else:
139-
logging.warn(f"Patching all the strings does not evade detection.")
130+
logging.warning(f"Patching all the strings does not evade detection.")
140131

141132
return detection_result
142133

@@ -275,9 +266,6 @@ def parse_pe(sample_file):
275266

276267
if __name__ == "__main__":
277268

278-
#g_scanner = VMWareAvast()
279-
#g_scanner = VMWareDeepInstinct()
280-
g_scanner = DockerWindowsDefender()
281269
parser = argparse.ArgumentParser()
282270

283271
parser.add_argument("-s", '--skip-strings', help="Skip strings analysis", action="store_true")
@@ -288,7 +276,22 @@ def parse_pe(sample_file):
288276
parser.add_argument('-c', '--section', help="Analyze provided section")
289277
parser.add_argument('-g', '--globals', help="Analyze global variables in .data section", action="store_true")
290278
parser.add_argument('-V', '--virus', help="Virus scan", action="store_true")
279+
parser.add_argument('-H', '--hide-section', help="Hide a section", type=str)
280+
parser.add_argument('-S', "--scanner", help="Antivirus engine", default="DockerWindowsDefender")
291281
g_args = parser.parse_args()
292282

283+
if g_args.scanner == "DockerWindowsDefender":
284+
g_scanner = DockerWindowsDefender()
285+
293286
pe = parse_pe(g_args.file)
287+
288+
if g_args.hide_section:
289+
copy_file = NamedTemporaryFile(delete=False)
290+
shutil.copy(pe.filename, copy_file.name)
291+
pe.filename = copy_file.name
292+
hide_section(pe, g_args.hide_section)
293+
logging.info(f"Dumped patched file @ {copy_file.name}")
294+
sys.exit(0)
295+
296+
294297
investigate(pe)

config.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"loadlibrary_path": "/home/toto/loadlibrary/mpclient",
3+
"loadlibrary_path_dir": "/home/toto/loadlibrary",
4+
"docker_loadlibrary_name": "loadlibrary-working",
5+
"avast_vmx": "/Users/vladimir/Virtual Machines.localized/Windows_10_Avast.vmwarevm/Windows_10_Avast.vmx",
6+
"kaspersky_vmx": "../../kasp.vmx",
7+
"deepinstinct_vmx": "../../Virtual Machines.localized/Windows_10_AV_DeepInstinct.vmwarevm/Windows_10_AV_DeepInstinct.vmx",
8+
"vmware_user": "toto",
9+
"vmware_passwd": "$crt1234!"
10+
}

config.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import json
2+
import os
3+
4+
CONFIG_FILE = os.path.join(os.path.dirname(__file__), "config.json")
5+
6+
7+
def get_value(value):
8+
9+
try:
10+
with open(CONFIG_FILE) as jsonfile:
11+
12+
data = json.load(jsonfile)
13+
14+
if value in data:
15+
return data[value]
16+
except Exception as e:
17+
import traceback
18+
traceback.print_exc()
19+
import os
20+
print(os.getcwd())
21+
raise Exception(e)
22+
23+
raise Exception(f"Unknown field: {value}. Available fields are: {data.keys()}")

find.py

+11-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#!/usr/bin/python
22

3-
import os
4-
import subprocess
5-
import re
6-
import sys
7-
import hexdump
3+
import logging
84
import string
9-
from tqdm import tqdm
10-
from concurrent import futures
5+
import sys
116
from collections import deque
12-
from intervaltree import Interval, IntervalTree
7+
from concurrent import futures
8+
9+
import hexdump
1310
from capstone import *
14-
from scanner import WindowsDefender, DockerWindowsDefender, VMWareDeepInstinct, VMWareKaspersky, VMWareAvast
15-
import logging
11+
from intervaltree import Interval, IntervalTree
12+
from tqdm import tqdm
13+
14+
import config
1615
import pe_utils
16+
from scanner import g_scanner
1717

1818
logging.basicConfig(filename='debug.log',
1919
filemode='a',
@@ -36,7 +36,7 @@
3636
IGNORE_START = 0
3737
IGNORE_END = 0x256 #todo use pefile to find the start of code
3838
GOAT_FILE = '/tmp/metsrv.x64.dll'
39-
WDEFENDER_INSTALL_PATH = '/home/vladimir/tools/loadlibrary/'
39+
WDEFENDER_INSTALL_PATH = config.get_value("loadlibrary_path_dir")
4040
MAX_THREADS = 10
4141
DEBUG_LEVEL = 1
4242
buffer = []
@@ -47,7 +47,6 @@
4747
cs = Cs(CS_ARCH_X86, CS_MODE_64)
4848
cs.detail = True
4949
cs.skipdata = True
50-
g_scanner = None
5150

5251

5352

@@ -296,9 +295,7 @@ def process_file(sample_file, start = 0, end=-1):
296295

297296

298297
def bytes_detection(filename, start=0, end=-1):
299-
global g_scanner
300298

301-
g_scanner = DockerWindowsDefender()
302299
# g_scanner = VMWareAvast()
303300
sample_file = filename
304301

find_bad_strings.py

+27-22
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
11
#!/usr/bin/python3
2-
import sys
3-
import string
4-
import os
5-
import subprocess
62
import dataclasses
3+
import logging
74
import re
8-
import random
5+
import subprocess
6+
import sys
97
import tempfile
8+
109
from tqdm import tqdm
11-
from itertools import islice
12-
from scanner import WindowsDefender, DockerWindowsDefender, VMWareKaspersky, VMWareAvast
13-
import logging
10+
11+
from scanner import g_scanner
1412

1513
logging.basicConfig(filename='debug.log',
1614
filemode='a',
1715
format='[%(levelname)-8s][%(asctime)s][%(filename)s:%(lineno)3d] %(funcName)s() :: %(message)s',
1816
datefmt='%Y/%m/%d %H:%M',
1917
level=logging.DEBUG)
2018

21-
BINARY = "/home/vladimir/dev/av-signatures-finder/test_cases/ext_server_kiwi.x64.dll"
19+
BINARY = "test_cases/ext_server_kiwi.x64.dll"
2220
ORIGINAL_BINARY = ""
23-
WDEFENDER_INSTALL_PATH = '/home/vladimir/tools/new_loadlibrary/loadlibrary/'
2421
DEBUG_LEVEL = 2 # setting supporting levels 0-3, incrementing the verbosity of log msgs
2522
LVL_ALL_DETAILS = 3 # everything
2623
LVL_DETAILS = 2 # only important details
2724
LVL_RES_ONLY = 1 # only results
2825
LVL_SILENT = 0 # quiet
29-
g_scanner = None
26+
3027

3128
@dataclasses.dataclass
3229
class StringRef:
@@ -340,7 +337,12 @@ def rec_bissect(binary, string_refs, blacklist):
340337
return blacklist
341338

342339

343-
half_nb_strings = len(string_refs) // 2
340+
try:
341+
half_nb_strings = len(string_refs) // 2
342+
except:
343+
print_dbg(f"Found it: f{repr(string_refs)}", LVL_RES_ONLY, False)
344+
blacklist.append(string_refs.index)
345+
return blacklist
344346
half1 = string_refs[:half_nb_strings]
345347
half2 = string_refs[half_nb_strings:]
346348
binary1 = binary
@@ -422,13 +424,10 @@ def rec_bissect(binary, string_refs, blacklist):
422424
"""
423425
def bissect(sample_file, blacklist = []):
424426

425-
global g_scanner
426427
global BINARY
427428

428429
BINARY = sample_file
429-
if g_scanner is None:
430-
g_scanner = DockerWindowsDefender()
431-
# g_scanner = VMWareAvast()
430+
432431
# no point in continuing if the binary is not detected as malicious already.
433432
assert(scan(sample_file) is True)
434433

@@ -477,20 +476,26 @@ def bissect(sample_file, blacklist = []):
477476
if len(blacklist) > 0:
478477
print_dbg(f"Found {len(blacklist)} signatures", LVL_DETAILS, True)
479478
print(blacklist)
479+
480+
for b in blacklist:
481+
string = next(filter(lambda x: x.index == b, str_refs))
482+
logging.info(f"String @ {hex(string.paddr)} should be patched: ")
483+
logging.info(string.content)
480484
tmpfile = "/tmp/newbin"
481-
if not validate_results(ORIGINAL_BINARY, tmpfile, blacklist, str_refs):
482-
print_dbg("Validation is ok !", LVL_DETAILS, True)
483-
else:
484-
print_dbg("Patched binary is still detected, retrying.", LVL_DETAILS, True)
485-
bissect("/tmp/newbin", blacklist)
485+
if ORIGINAL_BINARY != "":
486+
if not validate_results(ORIGINAL_BINARY, tmpfile, blacklist, str_refs):
487+
print_dbg("Validation is ok !", LVL_DETAILS, True)
488+
else:
489+
print_dbg("Patched binary is still detected, retrying.", LVL_DETAILS, True)
490+
bissect("/tmp/newbin", blacklist)
486491
else:
487492
print_dbg("No signatures found...", LVL_DETAILS, True)
488493
return blacklist
489494

490495

491496
if __name__ == "__main__":
492497

493-
g_scanner = DockerWindowsDefender()
498+
#g_scanner = DockerWindowsDefender()
494499

495500

496501
sample_file = BINARY

pe_utils.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,23 @@ def parse_strings_old(strings_data):
221221
return string_refs
222222

223223

224-
def parse_strings(filename, all_sections=False, min_length=5):
224+
def parse_strings(filename, all_sections=False, min_length=12):
225225
pipe = r2pipe.open(filename)
226226
pipe.cmd("aaa")
227227
# pipe.cmd("aaa")
228-
strings = pipe.cmdj("izzj")
228+
if all_sections:
229+
strings = pipe.cmdj("izzj")
230+
else:
231+
strings = pipe.cmdj("izj")
229232

230233
string_refs = []
231234

232235
for string in strings:
233236

234-
if string.get("size") < min_length:
237+
if string.get("length") < min_length:
238+
continue
239+
240+
if not string.get("section").startswith("."):
235241
continue
236242

237243
str_ref = StringRef()

scan.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
import subprocess
3+
import sys
4+
import re
5+
import config
6+
7+
WDEFENDER_INSTALL_PATH = config.get_value("loadlibrary_path")
8+
9+
current_dir = os.getcwd()
10+
os.chdir(os.path.dirname(WDEFENDER_INSTALL_PATH))
11+
command = [WDEFENDER_INSTALL_PATH, sys.argv[1]]
12+
p = subprocess.Popen(command, stdout=subprocess.PIPE,
13+
stderr=subprocess.STDOUT)
14+
15+
while (True):
16+
17+
retcode = p.poll() # returns None while subprocess is running
18+
out = p.stdout.readline().decode('utf-8', errors='ignore')
19+
print(out)
20+
m = re.search('Threat', out)
21+
22+
if m:
23+
print("Threat found\n")
24+
exit(-1)
25+
26+
if (retcode is not None):
27+
break
28+
29+
os.chdir(current_dir)
30+
exit(0)

0 commit comments

Comments
 (0)