Skip to content

Noise Introducing Generator | Glorified Evidence Remover

Notifications You must be signed in to change notification settings

kenleejl/Gernig

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

82 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gernig

Installation

Prerequisites

Clone the repository

git clone https://github.com/kokseen1/Gernig.git

Run the example

Ensure that target_program.exe is in the same directory.

cd Gernig
python example.py

Basic Usage

The following example shows how to add noise via the Python interface:

from gernig import Noiser
from gernig.modules import *

n = Noiser("program64.exe")  # Initialize with target binary

n.addNoise(PrintNoise("Hello world!"))  # Add PrintNoise module
n.addNoise(DnsNoise("google.com"))  # Add DnsNoise module

n.generate("output.exe")

Run the generated binary:

.\output.exe

Available Modules

The following shows the available modules that were implemented, what they are for, and how to use them.

Noise Generating Modules

NetworkNoise()

NetworkNoise is a network noise generator that generates network traffic by connecting to random IPs using the following protocols:

  • ssh
  • netcat
  • ftp
  • curl (http)
  • ping
from gernig.noiser import Noiser
from gernig.modules import NetworkNoise
n = Noiser("<filename>")
n.addAnalysis(NetworkNoise())
n.generate()

FileNoise()

FileNoise is a file noise generator that generates file activity by creating new files in the following directories:

  • Downloads
  • Documents
  • Pictures
  • Desktop
  • Videos

It creates files with the following extensions:

  • .ps1
  • .docx
  • .txt
  • .pptx
  • .exe
from gernig.noiser import Noiser
from gernig.modules import FileNoise
n = Noiser("<filename>")
n.addAnalysis(FileNoise())
n.generate()

DnsNoise()

DnsNoise is a DNS noise generator feature that queries for randomly generated domain names that are hardcoded into the binary at compile time.

Domain names are generated by using a dictionary wordlist under dns\wordlist.txt, where two words are randomly picked out of the wordlist and concatenated together with a random top level domain using a TLD wordlist under dns\tld.txt.

from gernig.noiser import Noiser
from gernig.modules import DnsNoise
n = Noiser("<filename>")
n.addAnalysis(DnsNoise())
n.generate()

TimeStomperNoise()

TimeStomper is a Time Stamp noise generator feature that modifies the file's Last Assessed, Last Modified and Last Created Date and Time.

Currently queries the directory for all user profile. Changes the file's time stamp in Documents, Downloads, Pictures and Videos.

from gernig.noiser import Noiser
from gernig.modules import TimeStomperNoise
n = Noiser("<filename>")
n.addAnalysis(TimeStomperNoise())
n.generate()

Environmental Analysis Modules

DnsAnalysis()

DnsAnalysis checks for valid DNS resolvers on the system by ensuring that actual domain names are getting resolved and not all domain names. If it is unable to resolve the DNS names for a quarter or more of the valid DNS names, or a quarter or more of the invalid DNS names are being resolved, then the program exits. The domain names it uses to query are hardcoded into the binary on compile time.

Domain names are not regenerated by default if the fake-domains.txt and resolved-domains.txt files exist, as domain names will then be taken from these text files. Domain names can be regenerated at compile time by passing the 'force' parameter to the DnsAnalysis class. Domain names are generated using the same algorithm as the DnsNoise class.

Parameter:

  • force: pass the string "force" to it to regenerate domain names to be used for this function; optional argument
  • num_domains: pass the number of domain names that you want to be used for doing DNS analysis, but keep in mind that the generation of domain names will take longer with a larger number of domain names. Default number of domain names generated for both real and fake domain names is 10. Must be used in conjunction with the 'force' parameter; optional argument
  • resolved_domains: a list of domains that can be resolved that you can specify. If the force parameter is specified then this is ignored. Optional argument.
  • fake_domains: a list of domains that cannot be resolved that you can specify. If the force parameter is specified then this is ignored. Optional argument.
from gernig.noiser import Noiser
from gernig.modules import DnsAnalysis
n = Noiser("<filename>")
n.addAnalysis(DnsAnalysis('force', 10))
n.generate()

MACAddrAnalysis()

It checks the MAC addresses of the host system to ensure that not all MAC address OUIs belong to virtual machine manufacturers.

Default MAC address OUIs to look out for:
00:05:69 (Vmware)
00:0C:29 (Vmware)
00:1C:14 (Vmware)
00:50:56 (Vmware)
00:15:5d (Hyper-V)
08:00:27 (VirtualBox)
52:54:00 (VirtualBox)
00:21:F6 (VirtualBox)
00:14:4F (VirtualBox)
00:0F:4B (VirtualBox)
00:1C:42 (Parallels)

Parameter:

  • blacklist: a list of MAC address OUIs to look out for; optional argument
from gernig.noiser import Noiser
from gernig.modules import MACAddrAnalysis
n = Noiser("<filename>")
n.addAnalysis(MACAddrAnalysis(['98:76:54', '12:34:56']))
n.generate()

CPUIDAnalysis()

It checks the CPU ID to ensure that it does not belong to a virtual machine CPU ID, and if the CPU ID belongs to the virtual machine CPU ID, then it terminates the program.

from gernig.noiser import Noiser
from gernig.modules import CPUIDAnalysis
n = Noiser("<filename>")
n.addAnalysis(CPUIDAnalysis())
n.generate()

ProcessAnalysis()

It checks the name of the processes running on the system if there are any blacklisted process names amongst them, and if it finds a blacklisted process name, then it terminates the program.

Default process names to look out for: "vmware.exe", "xenservice.exe", "vmsrvc.exe", "vboxservice.exe", "joeboxserver.exe", "prl_cc.exe"

Parameters:

  • process_list: a list of blacklisted process names; optional argument
from gernig.noiser import Noiser
from gernig.modules import ProcessAnalysis
n = Noiser("<filename>")
n.addAnalysis(ProcessAnalysis(["vmware.exe", "sandbox_process.exe"]))
n.generate()

SleepAnalysis()

It delays the execution of the program while testing if the sleep function is patched by the host system, and aborts execution if the program actual sleep timing is different from the time it was supposed to sleep.

Default time in milliseconds: 10000

Parameters:

  • sleep_time: time to delay program execution in milliseconds; optional argument
from gernig.noiser import Noiser
from gernig.modules import SleepAnalysis
n = Noiser("<filename>")
n.addAnalysis(SleepAnalysis(1000))
n.generate()

Evasive Measures Modules

EventlogBlind()

It kills the Event Logging service using an exploit, rendering any services that rely on the Windows Event Log useless.

from gernig.noiser import Noiser
from gernig.modules import EventlogBlind
n = Noiser("<filename>")
n.addBlind(EventlogBlind())
n.generate()

UPXBlind()

It packs the original executable with UPX to compress the binary's size.

from gernig.noiser import Noiser
from gernig.modules import EventlogBlind
n = Noiser("<filename>")
n.addBlind(UPXBlind())
n.generate()

Development Setup

Prerequisites

Gernig Development

  • loader32/64.exe - Main program that will dispatch noise modules as threads and load the target binary from memory
  • program32/64.exe - Sample target program used for testing, simulates a simple program loop

To develop and test core Gernig functionality outside of Python, build via Make:

cd gernig
make

Build for 32-bit:

make m32=1

Run on sample program:

loader64.exe program64.exe

Module Development

Each noise module is separated into their respective .cpp and .hpp files located in gernig/src/modules and gernig/include/modules respectively.

Modules are implemented as thread callback functions passed to std::thread, which will be dispatched from main.

In the following module function, the printLoop function will be launched as a thread and the argument msg will be printed to the console every second, alongside the target binary.

void printLoop(std::string msg)
{
    while (1)
    {
        std::cout << msg << std::endl;
        Sleep(1000);
    }
}

Preprocessor conditional directives are used to "pass information" from Python to C++, such as enabling a certain module or passing a string parameter:

defines.h:

#define _PRINT_NOISE_ENABLED
#define _PRINT_NOISE_TEXT "Hello world!"

This is automatically generated when you run the Noiser python class, and can be ignored when running from Python.

All the modules should be placed in individual conditional directives to allow for the user to control which modules are to be enabled using Python classes of those modules as shown below. The specific functions for the different modules should be run as a thread. If a function is required to be run finish before the execution of the actual program, use .join() function of the thread class to wait for the thread to finish running first before continuing with program execution. All blinding and analysis modules are each required to be run to completion before the run of other modules or the actual program itself, and as such it is placed closer to the top of the main.cpp file.

main.cpp:

#include <defines.h>

#ifdef _PRINT_NOISE_ENABLED
    std::thread t1(printLoop, _PRINT_NOISE_TEXT);
#endif

Finally, the original target binary is embedded into the program as an array of unsigned char in binexp.h, and is parsed and loaded directly from memory via LoadFromMemory by calling its entry point stored in pMemoryModule->exeEntry. Further obfuscation can be performed on this array if required.

binexp.h:

unsigned char BINARY_ARRAY[] = {
    0x4d, 0x5a, 0x90, 0x00, 0x03,
    ...
}

About

Noise Introducing Generator | Glorified Evidence Remover

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •