Strings & Import Analysis

Overview

Extracting readable strings and analyzing API imports are fundamental static analysis techniques. Strings reveal URLs, IP addresses, file paths, registry keys, error messages, and command-line arguments. Import analysis reveals which system APIs a binary calls, directly indicating its capabilities (networking, file I/O, process manipulation, encryption, etc.).

String Extraction

strings Command

# GNU Binutils (strings)
# https://www.gnu.org/software/binutils/

# Extract ASCII strings (default: minimum 4 characters)
strings sample.exe

# Set minimum string length
strings -n 8 sample.exe

# Extract wide-character (UTF-16LE) strings (common in Windows malware)
strings -e l sample.exe

# Show file offset of each string (hex)
strings -t x sample.exe

# Show file offset (decimal)
strings -t d sample.exe

# Scan entire file, not just data sections (this is now the default behaviour)
strings -a sample.exe

# Combine: both ASCII and wide strings with offsets
strings -t x sample.exe > strings_ascii.txt
strings -t x -e l sample.exe > strings_wide.txt

rabin2 String Extraction

# radare2
# https://github.com/radareorg/radare2

# Extract strings from data sections
rabin2 -z sample.exe

# Extract strings from the entire binary
rabin2 -zz sample.exe

# Extract wide strings (UTF-16)
r2 -e bin.str.enc=utf16le -qc 'izz' sample.exe

What to Look For in Strings

Category Examples
URLs / domains http://, https://, .com, .net, .onion
IP addresses 192.168., 10.0., any dotted quad
File paths C:\Windows\, /tmp/, %APPDATA%
Registry keys HKLM\, HKCU\, Software\Microsoft\Windows\CurrentVersion\Run
Commands cmd.exe, /bin/sh, powershell, wget, curl
Crypto artifacts -----BEGIN, AES, RSA, base64-encoded blobs
User agents Mozilla/, User-Agent:
Passwords / credentials password, admin, login, hardcoded tokens
Error / debug messages Function names, debug output, compiler artifacts
Mutex names Global\, named mutexes for single-instance checks

Filtering Interesting Strings

# GNU Binutils (strings)
# https://www.gnu.org/software/binutils/

# URLs and domains
strings sample.exe | grep -iE 'https?://|www\.|\.com|\.net|\.org'

# IP addresses
strings sample.exe | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'

# File paths (Windows)
strings sample.exe | grep -iE '[A-Z]:\\|%[A-Z]+%'

# File paths (Linux)
strings sample | grep -E '^/(tmp|etc|var|bin|usr|home)/'

# Registry keys
strings sample.exe | grep -iE 'HKLM|HKCU|HKCR|CurrentVersion\\Run'

# Email addresses
strings sample.exe | grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'

# Base64-encoded strings (long alphanumeric sequences)
strings sample.exe | grep -E '^[A-Za-z0-9+/]{20,}={0,2}$'

# Commands and shells
strings sample.exe | grep -iE 'cmd\.exe|powershell|/bin/(sh|bash)|wget|curl'

Encoded and Obfuscated Strings

Malware frequently encodes or encrypts strings to evade detection. Common techniques include:

Technique Detection Approach
XOR encoding Look for repeated XOR key patterns; high entropy regions
Base64 Decode long alphanumeric strings with base64 -d
ROT13 / Caesar Try rotational shifts on suspicious strings
Stack strings Single characters pushed to stack (visible in disassembly)
RC4 / AES encrypted Requires key recovery during dynamic analysis or reversing
String stacking Characters assembled one at a time in code
# Decode a base64 string found in the binary
echo 'aHR0cDovL2V4YW1wbGUuY29t' | base64 -d

# XOR brute-force with single-byte key (Python one-liner)
python3 -c "
data = open('sample.exe','rb').read()
for key in range(1, 256):
    decoded = bytes(b ^ key for b in data[0x1000:0x1100])
    if b'http' in decoded or b'.exe' in decoded:
        print(f'Key: {key:#04x}, Decoded: {decoded}')
"

Import Analysis

PE Imports with pefile

# pefile
# https://github.com/erocarrera/pefile
import pefile

pe = pefile.PE('sample.exe')

# List all imports by DLL
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
    for entry in pe.DIRECTORY_ENTRY_IMPORT:
        print(f"\n{entry.dll.decode()}")
        for imp in entry.imports:
            name = imp.name.decode() if imp.name else f"ordinal_{imp.ordinal}"
            print(f"  {hex(imp.address):12s}  {name}")

# Import hash (same source code = same imphash)
print(f"\nImphash: {pe.get_imphash()}")

PE Imports with rabin2

# radare2
# https://github.com/radareorg/radare2

# List all imports
rabin2 -i sample.exe

# List imports grouped by library
rabin2 -i sample.exe | sort -t. -k1

ELF Imports

# GNU Binutils (readelf)
# https://www.gnu.org/software/binutils/

# Show dynamic symbols (imports)
readelf --dyn-syms sample | grep -E 'UND|FUNC'

# Show shared library dependencies
readelf -d sample | grep NEEDED

# radare2
# https://github.com/radareorg/radare2
rabin2 -i sample

Suspicious Import Categories

Process Manipulation:

DLL Function Capability
kernel32.dll CreateRemoteThread Inject thread into another process
kernel32.dll VirtualAllocEx Allocate memory in another process
kernel32.dll WriteProcessMemory Write to another process's memory
kernel32.dll OpenProcess Open handle to another process
ntdll.dll NtUnmapViewOfSection Process hollowing
kernel32.dll QueueUserAPC APC injection

Execution:

DLL Function Capability
kernel32.dll CreateProcessA/W Launch a new process
kernel32.dll WinExec Execute a command
shell32.dll ShellExecuteA/W Execute file/URL
msvcrt.dll system Execute shell command

File System:

DLL Function Capability
kernel32.dll CreateFileA/W Create or open files
kernel32.dll ReadFile, WriteFile Read/write file contents
kernel32.dll DeleteFileA/W Delete files
kernel32.dll CopyFileA/W Copy files
kernel32.dll MoveFileA/W Move/rename files
kernel32.dll FindFirstFileA/W Directory enumeration

Networking:

DLL Function Capability
ws2_32.dll socket, connect, bind Raw socket operations
ws2_32.dll send, recv Data transfer
wininet.dll InternetOpenA/W Initialize WinINet
wininet.dll InternetOpenUrlA/W Open a URL
wininet.dll HttpSendRequestA/W Send HTTP request
urlmon.dll URLDownloadToFileA/W Download file from URL
winhttp.dll WinHttpOpen, WinHttpSendRequest HTTP client

Persistence:

DLL Function Capability
advapi32.dll RegSetValueExA/W Write registry value
advapi32.dll RegCreateKeyExA/W Create registry key
advapi32.dll CreateServiceA/W Install a service
kernel32.dll CopyFileA/W Copy self to persist location

Evasion and Anti-Analysis:

DLL Function Capability
kernel32.dll IsDebuggerPresent Detect debugger
kernel32.dll CheckRemoteDebuggerPresent Detect remote debugger
kernel32.dll GetTickCount Timing check (sandbox evasion)
kernel32.dll Sleep Delay execution (sandbox evasion)
kernel32.dll VirtualProtect Change memory permissions (unpack)

Encryption:

DLL Function Capability
advapi32.dll CryptAcquireContextA/W Initialize crypto provider
advapi32.dll CryptEncrypt, CryptDecrypt Encrypt/decrypt data
advapi32.dll CryptGenKey Generate encryption key
bcrypt.dll BCryptEncrypt, BCryptDecrypt Modern crypto API

Minimal Imports (Red Flag)

Malware that resolves APIs at runtime via GetProcAddress or LdrGetProcedureAddress will have very few static imports — often just kernel32.dll with LoadLibraryA and GetProcAddress. This is a strong indicator of:

  • Packed/encrypted binaries that resolve imports after unpacking
  • Malware intentionally hiding capabilities from static import analysis
  • Shellcode loaders
# pefile
# https://github.com/erocarrera/pefile
import pefile

pe = pefile.PE('sample.exe')

# Count total imports
total = 0
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
    for entry in pe.DIRECTORY_ENTRY_IMPORT:
        total += len(entry.imports)

print(f"Total imports: {total}")
# Very low count (< 10) with LoadLibraryA + GetProcAddress = suspicious

Export Analysis

Exports are functions a DLL exposes for other modules to call. Malware DLLs often use exports to provide entry points for different functionality.

# pefile
# https://github.com/erocarrera/pefile
import pefile

pe = pefile.PE('sample.dll')

if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
    for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
        name = exp.name.decode() if exp.name else "N/A"
        print(f"  Ordinal: {exp.ordinal}  Name: {name}  "
              f"Address: {hex(pe.OPTIONAL_HEADER.ImageBase + exp.address)}")

Suspicious export names include DllRegisterServer (COM registration), ServiceMain (service entry), and generic names like Start, Run, Init.

References

Tools

Official Documentation