Most if not all anti virus application work based on file signatures on disk. They have a large database of specific byte patterns, and they look for one or more byte patterns within a file. Some of the more advanced anti virus applications have additional features such as heuristics detection – i.e. looking for suspicious markers in what the application actually does. We’re trying to target basic anti virus signature matching. Currently our ‘nc.exe’ binary is being detected as malicious by AVG, and we want to know which part exactly is triggering the alert.

The utility listed below will allow us to split our binary up into increasing sizes. Using the command:

# ./ nc/nc.exe 100
Creating 593 files. ^C now if this is not what you want...

We will create versions of nc.exe of increasing sizes. As we have specified ‘100’ bytes, nc.exe.0 will be 100 bytes in size, nc.exe.1 will be 200 bytes in size, all the way to the original size (59392) which will require 593 files to be created.

Once this is done, we can ship this directory over to our AV machine and run a scan. Everything from nc.exe.0 to nc.exe.162 is clean, whilst nc.exe.163 to nc.exe.593 is detected and quarantined. We now know that something in the last 100 bytes of nc.exe.163 is triggering the pattern match.

ls -al nc.exe.163
-rw-r--r-- 1 root root 16400 2013-04-18 16:50 nc.exe.163

nc.exe.163 is 16400 bytes in size, and therefore, something between 16300 and 16400 is the trigger. Now lets split that down further, this time specifying the offset of 16300 and increments of 10 bytes:

# ./ nc/nc.exe.163 10 16300
Creating 10 files. ^C now if this is not what you want...

Now let’s ship that directory of 10 files over and let the AV scan it. Files between nc.163.0 and nc.exe.163.7 are undetected whilst nc.163.8 to nc.163.10 are detected. Let’s look at the last 10 bytes of nc.163.8 with hexdump

# ls -al nc.exe.163.8 
-rw-r--r-- 1 root root 16390 2013-04-18 16:57 nc.exe.163.8

# dd if=nc.exe.163.8 bs=1 skip=16380 count=10 2>/dev/null|hexdump
0000000 cccc cccc 8b55 6aec 68ff               

# dd if=nc.exe.163.8 bs=1 skip=16380 count=10 2>/dev/null|ndisasm -u -
00000000  CC                int3
00000001  CC                int3
00000002  CC                int3
00000003  CC                int3
00000004  55                push ebp
00000005  8BEC              mov ebp,esp
00000007  6AFF              push byte -0x1
00000009  68                db 0x68

The final ’68’ has been interpreted incorrectly as it’s the first byte of the next command sequence, so we’ll focus on the remaining 9. The ‘\xCC’ software interrupts can most likely be replaced with nops (\x90). Given the space that we have available, it’s not possible to rewrite the next sequences without additional creativity. As the push ebp; mov ebp, esp is the standard function prolog, it is highly unlikely that these are being looked for in any capacity.

We edit ‘cc cc cc cc’ and replace it with ’90 90 90 90′ using XVI32, and then rescan the application. This was sufficient and our binary now passes antivirus detection. This was only a very rudimentary AV bypass. In other cases, we may need to make more creative modifications to the binary such as hollowing out space, using different code sequences, encoding parts of the binary and so on.


#usage ./ <file> <byte stepping>
#Author npn <npn at iodigitalsec dot com>

usage() {
	echo "Usage: $0 <file> <step> [offset]"

if [ -z $1 ]; then
	exit 1

if [ -z $2 ]; then
	exit 1

if [ ! -f $1 ]; then
	echo "File: " $1 " not found"
	exit 1

if [ -z $3 ]; then

FILESIZE=$(ls -al $1 |cut -d " " -f 5)

FILENO=$(echo "("${FILESIZE}"-"${offset}")/"${2}|bc)
echo "Creating ${FILENO} files. ^C now if this is not what you want..."
sleep 2

echo "Running..."

let sizectr=$2+$offset

while [ $sizectr -le $FILESIZE ]; do
	dd if=${1} of=${1}.${ctr} bs=1 count=${sizectr} >/dev/null 2>&1
	let ctr=$ctr+1
	let sizectr=$sizectr+$2
echo "Done"