Post

Gozi / ISFB

Gozi / ISFB

1. Executive Summary

The analyzed artifact is a packed 32-bit Windows PE DLL associated with the Gozi/ISFB malware family. The visible packed layer implements loader behavior, encrypted string storage, manual API resolution, executable memory allocation, and staged control transfer into an unpacked DLL image.

The original packed sample hides key runtime strings behind a compact byte-subtraction cipher. The relevant packed-stage decoder is located at 0x0040BDF0, with the byte-transform helper at 0x00401270. Recovered plaintext from this layer includes ntdll.dll, kernel32.dll, LdrGetProcedureAddress, and VirtualAlloc.

After unpacking and remapping, the next stage is a 32-bit DLL with a stale PE header ImageBase of 0x10000000, while code operands target 0x0040xxxx. The correct effective analysis base is therefore 0x00400000. Failure to rebase breaks absolute references, IAT references, and control-flow recovery.

The unpacked/remapped DLL contains two important decode paths:

RoutineAddressPurpose
Packed string decoder0x0040BDF0Recovers loader strings in the packed stage.
Byte helper0x00401270Performs the rolling byte subtraction transform.
Resource/string-table resolver0x004011DEResolves and decrypts compressed metadata-backed entries.
Custom decompressor0x004016EEExpands compressed resource entries.
.bss decoder wrapper0x0040197CReconstructs runtime API-name data in .bss.
.bss transform helper0x00401FD8Dword delta transform used by the .bss decode path.

Primary capability observed in the inspected layers: staged loader execution, encrypted API-name storage, dynamic API resolution, private heap initialization, thread creation, Native API preparation, section mapping primitives, and memory protection control.


2. File Identification & IoCs

2.1 Packed DLL

FieldValue
File size442,368 bytes
File typePE32 DLL
Architecturex86 / Intel 80386
Image base0x00400000
Entry pointRVA 0x00001430 / VA 0x00401430
MD5f28f39ada498d66c378fd59227e0f215
SHA-11c9c0584ad51f5be3f16b334d758c88b8cdb7b38
SHA-2560a66e8376fc6d9283e500c6e774dc0a109656fd457a0ce7dbf40419bc8d50936
Linker / compile timestamp2004-08-04 07:57:05 UTC
PDB pathd:\in\the\town\where\ahung.pdb
Export statusNo export observed in the packed layer

The packed-stage timestamp should not be used as attribution. The section layout and loader behavior indicate deliberate packing/protection.

2.2 Unpacked / Remapped DLL

FieldValue
Filename_unpacked_gozi_remap.bin
Container_unpacked_gozi_remap.zip
ZIP passwordinfected
Internal export DLL nameera.dll
File size57,344 bytes / 0xE000
File typePE32 DLL
Architecturex86 / Intel 80386
SubsystemWindows GUI
Effective analysis base0x00400000
PE header ImageBase0x10000000
Entry pointRVA 0x1846 / effective VA 0x401846
Exported functionDllRegisterServer at RVA 0x11C2 / effective VA 0x4011C2
Compilation timestamp2022-04-26 19:11:46 UTC / 0x626843F2
MD5fe0b06118973026ea5292ab09cc201e2
SHA-10aaaabb5ef0084d175a3773688273b0943ed81e2
SHA-2567226f419ba40c25ac736484149163f0769c59c030ec0b91d3194d2dbf685ee99

2.3 Extracted Decrypted Resource Output

FieldValue
Output namegozi_dec_02d8_9e154a0c.bin
Source table entry0x2D8
Source RVA0x6400
Source file offset0x6400
Decrypted size0xAE00 bytes
First DWORD fix key0xD8E1F12F
Expected fixed headerMZ / 4D 5A 90 00
MD584667eac73ed93b5ec82ba94082e7c81
SHA-198cc4f958e12928f9bf189bbed515afe1c635be7
SHA-2563c6abfece35d9dae5eebd0cc855d02615ed5f5c649bbeb55b27ef23003610a30

2.4 Network IoCs

No C2 domain, IP address, URI, or port was recovered from the inspected stages. The available artifacts are loader/decryption layers, not a confirmed network-beaconing configuration stage.

2.5 Host IoCs

TypeValueConfidenceNotes
Packed DLL SHA-2560a66e8376fc6d9283e500c6e774dc0a109656fd457a0ce7dbf40419bc8d50936HighOriginal submitted packed sample.
Unpacked DLL SHA-2567226f419ba40c25ac736484149163f0769c59c030ec0b91d3194d2dbf685ee99HighCurrent unpacked/remapped file used for stage 7 analysis.
PDB pathd:\in\the\town\where\ahung.pdbMediumStatic artifact from packed DLL; may be noise.
Event objectRuntime suppliedLowCreateEventA imported/used, but plaintext object name was not recovered in this pass.
Registry keyNot observedN/ANo registry persistence confirmed from the inspected stage.
MutexNot observedN/ANo mutex recovered statically.
Dropped fileNot observedN/ANo filesystem drop confirmed statically.

3. Static Analysis

3.1 Packed DLL Section Characteristics

Packed DLL entropy profile

SectionRVAVirtual SizeRaw OffsetRaw SizeCharacteristicsEntropyAssessment
.text0x000010000x0000B7100x000010000x0000C000Code / execute / read1.022Low entropy loader stub / sparse code.
.rdata0x0000D0000x000010730x0000D0000x00002000Initialized data / read3.716Import descriptors, metadata, static strings.
.data0x0000F0000x000079D00x0000F0000x00006000Initialized data / read-write6.027Mixed data, encrypted buffers, writable state.
.crt0x000170000x0001DC8E0x000150000x0001E000Initialized data / read-write7.982High entropy packed/encrypted payload data.
.erloc0x000350000x0002CA4F0x000330000x0002D000Initialized data / read-write7.981Non-standard relocation-like section, likely packed data.
.rsrc0x000620000x00009F280x000600000x0000A000Initialized data / read6.517Resource section with elevated entropy.

The packed file uses abnormal section naming and high-entropy writable sections. .crt and .erloc are the strongest indicators of embedded encrypted/compressed material.

3.2 Unpacked DLL Section Characteristics

SectionRVAVirtual SizeRaw OffsetRaw SizeEntropyNotes
.text0x10000x16B70x10000x16B76.551Code, loader logic, decompressor, SEH helpers.
.rdata0x30000x059C0x30000x059C5.579Import descriptors, IAT, metadata.
.data0x40000x025C0x40000x025C0.321Runtime state and globals.
.bss0x50000x02DC0x50000x02DC7.620High-entropy encoded runtime API-name data.
.reloc0x60000x80000x60000x80007.385Compressed/encrypted blob storage, not only relocation data.

The .bss and .reloc names are misleading. Both sections carry encoded or compressed runtime material.

3.3 Imports and Exports

Packed import view

Unpacked DLL Imports

DLLAPIs
ntdll.dll_snwprintf, memset, NtQuerySystemInformation, _aulldiv, RtlUnwind, NtQueryVirtualMemory
KERNEL32.dllSetThreadAffinityMask, CloseHandle, HeapAlloc, SetThreadPriority, Sleep, ExitThread, lstrlenW, GetLastError, GetExitCodeThread, HeapCreate, HeapDestroy, GetCurrentThread, SleepEx, WaitForSingleObject, InterlockedDecrement, InterlockedIncrement, HeapFree, GetModuleFileNameW, SetLastError, GetModuleHandleA, VirtualProtect, OpenProcess, CreateEventA, GetLongPathNameW, GetVersion, GetCurrentProcessId, TerminateThread, QueueUserAPC, CreateThread, GetProcAddress, LoadLibraryA, VirtualFree, VirtualAlloc, MapViewOfFile, GetSystemTimeAsFileTime, CreateFileMappingW
ADVAPI32.dllConvertStringSecurityDescriptorToSecurityDescriptorA

Notable primitives: VirtualAlloc, VirtualProtect, CreateThread, QueueUserAPC, OpenProcess, MapViewOfFile, CreateFileMappingW, NtQueryVirtualMemory, and NtQuerySystemInformation.

The unpacked DLL exports DllRegisterServer, consistent with a COM-registration style entry point but not necessarily benign COM behavior.


4. Behavioral & Dynamic Analysis

4.1 Execution Handling

The packed sample acts as a loader. It resolves minimal APIs, allocates executable memory, reconstructs the next image, applies memory permissions, and transfers control into the unpacked DLL.

The unpacked DLL entry point is 0x401846. Its initialization path performs process/thread attach accounting, creates a private heap, prepares runtime state, decodes internal data, and starts worker logic.

AddressBehavior
0x401846DLL entry-style dispatcher. Handles attach/detach reason values.
0x401863Uses InterlockedIncrement for attach state tracking.
0x40187DCreates a private heap via HeapCreate.
0x4018A6Calls SEH/setup helper at 0x401EFE.
0x4018ACEnters worker-thread setup through 0x402009.
0x40197CDecodes .bss, validates checksum, and copies decoded bytes back.
0x401BC9Uses decoded/resolved data in timing/sleep logic.

4.2 Process Tree / Injection / Persistence

No process hollowing, registry persistence, dropped file, or network callback was confirmed from the inspected stage. However, the import set and decoded .bss API names expose primitives commonly used by loaders and injection-capable malware:

  • ZwCreateSection
  • ZwMapViewOfSection
  • ZwUnmapViewOfSection
  • ZwWriteVirtualMemory
  • ZwProtectVirtualMemory
  • ZwSetContextThread
  • ZwGetContextThread
  • QueueUserAPC
  • CreateThread
  • OpenProcess

The safest conclusion is that this stage prepares mapping/injection capability, but the full injection target and C2 configuration were not present in plaintext in the submitted layer.


5. Deep Dive: Packed Stage String Decryption

5.1 Scope

The packed stage contains a string decryption routine at 0x0040BDF0. The helper at 0x00401270 performs a byte subtraction transform using a rolling index into a 16-byte key.

5.2 Byte Helper Function: 0x00401270

Byte helper in decompiler

00401270  push ebp
00401271  mov  ebp, esp
00401273  push esi
00401274  mov  al, byte ptr [ebp+14h]     ; key byte
00401277  mov  ecx, dword ptr [ebp+10h]   ; index
0040127A  mov  edx, dword ptr [ebp+0Ch]   ; encrypted source
0040127D  mov  esi, dword ptr [ebp+08h]   ; destination
00401280  mov  ah, byte ptr [edx+ecx]
00401283  sub  ah, al
00401285  mov  byte ptr [esi+ecx], ah
00401288  pop  esi
00401289  pop  ebp
0040128A  ret

Reconstructed helper:

1
2
3
void transform_byte(uint8_t *dst, const uint8_t *src, uint32_t i, uint8_t key_byte) {
    dst[i] = src[i] - key_byte;
}

5.3 Decoder Loop: 0x0040BDF0

The malware does not use XOR for this layer. It uses byte subtraction with a 16-byte rolling key.

Key at 0x0040DBF6:

1
EC FB 05 08 DC D1 23 6F 67 44 5F 42 D8 77 DC 56

Algorithm:

1
2
3
4
5
6
7
8
9
10
void decrypt_string(uint8_t *dst, const uint8_t *src, uint32_t len) {
    static const uint8_t key[16] = {
        0xEC, 0xFB, 0x05, 0x08, 0xDC, 0xD1, 0x23, 0x6F,
        0x67, 0x44, 0x5F, 0x42, 0xD8, 0x77, 0xDC, 0x56
    };

    for (uint32_t i = 0; i < len; i++) {
        dst[i] = (uint8_t)(src[i] - key[i & 0x0F]);
    }
}

Inverse operation, useful for validation:

1
enc[i] = (uint8_t)(plain[i] + key[i & 0x0F]);

Decoder loop highlight

The decoder iterates over an encrypted buffer, applies the helper per byte, and writes plaintext back into the destination buffer. The key schedule is short and cyclic. The transform is reversible without running the malware.

Recovered packed-stage plaintext strings:

1
2
3
4
ntdll.dll
kernel32.dll
LdrGetProcedureAddress
VirtualAlloc

5.4 Manual API Resolution

The recovered strings support a loader path that manually resolves LdrGetProcedureAddress and VirtualAlloc. This reduces reliance on a clear static import table and delays key API visibility until runtime.

5.5 Anti-Analysis Notes

TechniqueEvidence
Packed high-entropy regions.crt, .erloc, and .rsrc entropy profile.
Encrypted API stringsPacked-stage string decoder at 0x0040BDF0.
Manual API resolutionRecovered LdrGetProcedureAddress and VirtualAlloc.
Loader control transferDynamic unpacking into memory before remapped-stage execution.

6. Dynamic Unpacking and Remap

6.1 Breakpoints Used

The unpacking workflow used memory-allocation and protection pivots to identify the unpacked image in memory.

VirtualAlloc and VirtualProtect breakpoints

Recommended breakpoint targets for this style of loader:

APIPurpose
VirtualAllocCatch new image allocation.
VirtualProtectCatch transition to executable permissions.
WriteProcessMemory / ZwWriteVirtualMemoryCatch remote/local image write if used.
CreateThread / QueueUserAPCCatch execution handoff.
LoadLibraryA/W and GetProcAddressCatch dynamic API resolution.

6.2 Unpacked Image in Memory

Unpacked image in memory

The unpacked dump contains a valid PE-like image and a working import table. The entry point used for analysis is 0x401846 after rebasing to 0x00400000.

6.3 Remap Correction

Remap before and after

The remapped file keeps a stale PE header image base of 0x10000000, while absolute code references point to 0x0040xxxx. The correct static analysis workflow is:

  1. Load the dumped DLL.
  2. Rebase to 0x00400000.
  3. Re-run analysis.
  4. Repair function boundaries where the unpacker damaged normal metadata.
  5. Rebuild imports/xrefs around 0x4030xx IAT references.

7. Unpacked and Remapped DLL Analysis

7.1 Rebasing Issue

The PE Optional Header reports ImageBase = 0x10000000, but the code uses absolute operands such as:

40146A  ff 15 54 30 40 00    call dword ptr ds:0x403054 ; GetModuleHandleA
401485  ff d7                call edi                    ; GetProcAddress
4019D2  ff 15 88 30 40 00    call dword ptr ds:0x403088 ; VirtualAlloc

These operands prove the effective base is 0x00400000.

7.2 Resource/String-Table Resolver: 0x4011DE

The resolver derives two values from global key material:

1
2
entry_tag   = (global_key ^ 0x150E) & 0xFFFF;
table_delta = global_key ^ 0x69B25F5C;

Recovered values:

1
2
3
global_key  = 0x69B25F44
entry_tag   = 0x4A4A
table_delta = 0x18

The metadata table begins at:

1
2
PE + SizeOfOptionalHeader + ((NumberOfSections + 1) * 0x28) + table_delta
= 0x2D8

Recovered table entry:

FieldValue
Table offset0x2D8
Entry tag0x4A4A
Flags0x21
XOR key0xD8E1F12F
Selector0x9E154A0C
Data RVA0x6400
Data file offset0x6400
Decrypted size0xAE00

Relevant assembly:

401204  8b ce                 mov ecx, esi
401206  81 f1 0e 15 00 00     xor ecx, 150Eh
401212  0f b7 c9              movzx ecx, cx
401215  81 f6 5c 5f b2 69     xor esi, 69B25F5Ch
401236  8b 45 10              mov eax, [ebp+10h]
40123D  39 46 08              cmp [esi+8], eax
401248  8b 46 10              mov eax, [esi+10h]
401264  8b 46 0c              mov eax, [esi+0Ch]
40126A  e8 7f 04 00 00        call 4016EEh
401281  8b 46 04              mov eax, [esi+4]
401284  31 03                 xor [ebx], eax

The flags & 1 branch invokes the decompressor. After decompression, the first DWORD of the output buffer is XOR-fixed using the entry key.

1
2
3
compressed output first DWORD : 0xD871AB62
XOR key                       : 0xD8E1F12F
result                        : 0x00905A4D => 4D 5A 90 00

7.3 Custom Decompressor: 0x4016EE

The decompressor is bitstream-based and uses MSB-first bit extraction. Its structure is compatible with an aPLib-style back-reference depacker.

Pseudocode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
out[0] = src[0];
src++;

while (!done) {
    if (getbit() == 0) {
        *dst++ = *src++;
    } else if (getbit() == 0) {
        distance = gamma_decode();
        length = gamma_decode();
        length += threshold_adjust(distance);
        copy_from_backref(distance, length);
    } else if (getbit() == 0) {
        token = *src++;
        distance = token >> 1;
        length = (token & 1) + 2;
        if (distance == 0)
            break;
        copy_from_backref(distance, length);
    } else {
        distance = read_4_bits();
        *dst++ = distance ? dst[-distance] : 0;
    }
}

Length adjustment at 0x401E48:

1
2
3
4
5
6
if (distance < 0x80)
    length += 2;
if (distance >= 0x500)
    length += 1;
if (distance >= 0x7D00)
    length += 1;

7.4 Anti-Analysis Observations

TechniqueEvidence
Stale / incorrect image baseHeader says 0x10000000; code operands target 0x0040xxxx.
Encoded high-entropy sections.bss and .reloc store encoded/compressed data.
Runtime API resolutionLoader resolves APIs through decoded strings and GetProcAddress.
Runtime memory inspectionUses NtQueryVirtualMemory.
System information queryUses NtQuerySystemInformation.
Thread and timing controlUses SetThreadAffinityMask, SetThreadPriority, SleepEx, WaitForSingleObject.
SEH scaffoldingCustom SEH helpers around 0x402228, 0x40227C, and related routines.

8. .bss Runtime Decode

The remapped stage keeps high-entropy encoded data in a pseudo-.bss section. This is separate from the 0x4011DE resource/string-table resolver.

Relevant routines:

VAPurpose
0x401922Locates the section header named .bss and returns its RVA/size.
0x40197CMain .bss decode wrapper; allocates scratch memory, decodes data, validates checksum, copies bytes back.
0x401FD8Dword delta transform loop.
0x40212BInternal memcpy-style routine.

Transform:

1
2
3
key  = dword(0x4030B8) + dword(0x4030BC) + bss_rva + seed - 1
out  = encoded_dword + previous_encoded_dword - key
stop = first zero encoded_dword

Recovered values:

1
2
3
4
5
6
.bss RVA      = 0x5000
.bss size     = 0x2DC
valid seed    = 0x13
key           = 0x5292F685
checksum      = 0x69B25F44
marker offset = 0x1BA

Decoded .bss strings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NTDLL.DLL
NTDSAPI.DLL
KERNEL32.DLL
IsWow64Process
Wow64EnableWow64FsRedirection
ZwCreateSection
ZwMapViewOfSection
ZwUnmapViewOfSection
RtlNtStatusToDosError
ZwClose
ZwSetContextThread
ZwGetContextThread
ZwWow64ReadVirtualMemory64
ZwWow64QueryInformationProcess64
kernelbase
LdrRegisterDllNotification
LdrUnregisterDllNotification
ZwWriteVirtualMemory
ZwProtectVirtualMemory
LoadLibraryA

These strings explain the later Native API resolution path and strongly indicate section-mapping and memory-modification capability.


9. MITRE ATT&CK Mapping

TacticTechniqueEvidence
Defense EvasionT1027 Obfuscated/Compressed Files and InformationPacked high-entropy sections, encrypted strings, compressed internal blob.
Defense EvasionT1140 Deobfuscate/Decode Files or InformationRuntime string/resource decryption and .bss reconstruction.
Defense EvasionT1497 Virtualization/Sandbox EvasionEnvironment and memory query primitives through NtQuerySystemInformation and NtQueryVirtualMemory; no full VM check confirmed.
ExecutionT1055 Process InjectionNative APIs and imports support section mapping and remote memory modification; injection flow not fully confirmed in submitted stage.
ExecutionT1106 Native APIDecoded Zw* names and imported Native API usage.
Privilege / Defense EvasionT1098 / local manipulation not confirmedNo registry/service/task persistence confirmed; do not overclaim.

10. Detection Engineering

10.1 YARA Rule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
rule MAL_Gozi_ISFB_Loader_Unpacked_Remapped_Stage
{
    meta:
        description = "Gozi/ISFB unpacked/remapped loader stage with encoded .bss and resource resolver"
        author = "os1ris"
        scope = "file"
        malware_family = "Gozi/ISFB"
        sha256_unpacked = "7226f419ba40c25ac736484149163f0769c59c030ec0b91d3194d2dbf685ee99"

    strings:
        $s1 = "DllRegisterServer" ascii
        $s2 = "ConvertStringSecurityDescriptorToSecurityDescriptorA" ascii
        $s3 = "NtQueryVirtualMemory" ascii
        $s4 = "NtQuerySystemInformation" ascii

        $bss_name = ".bss" ascii
        $reloc_name = ".reloc" ascii

        // 401206: xor ecx, 150Eh ; 401215: xor esi, 69B25F5Ch
        $resolver_key_ops = { 81 F1 0E 15 00 00 [0-16] 81 F6 5C 5F B2 69 }

        // 401284: xor [ebx], eax after decompression output
        $first_dword_fix = { 8B 46 04 31 03 }

    condition:
        uint16(0) == 0x5A4D and
        filesize < 2MB and
        3 of ($s*) and
        all of ($resolver_key_ops, $first_dword_fix)
}

10.2 Detection Notes

  • Avoid hash-only detection. Use section characteristics, resolver constants, and API clusters.
  • The ImageBase mismatch is useful for triage, but not stable enough as a single detection condition.
  • The .bss and .reloc entropy pattern is a good hunting signal for this unpacked/remapped artifact.

Appendix A: References

  • MITRE ATT&CK: Obfuscated Files or Information — https://attack.mitre.org/techniques/T1027/
  • MITRE ATT&CK: Deobfuscate/Decode Files or Information — https://attack.mitre.org/techniques/T1140/
  • MITRE ATT&CK: Process Injection — https://attack.mitre.org/techniques/T1055/
  • MITRE ATT&CK: Native API — https://attack.mitre.org/techniques/T1106/
  • Microsoft PE Format — https://learn.microsoft.com/en-us/windows/win32/debug/pe-format

Appendix B: Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import argparse
import struct
from pathlib import Path

BASE = 0x400000
BSS_RVA = 0x5000
BSS_OFF = 0x5000
BSS_SIZE = 0x2DC
K0 = 0x20727041
K1 = 0x32203632
CHECK = 0x69B25F44

def u32(b, o):
    return struct.unpack_from('<I', b, o)[0]

def decode_bss(pe, seed):
    src = pe[BSS_OFF:BSS_OFF + BSS_SIZE] + b'\x00' * (0x1000 - BSS_SIZE)
    dst = bytearray(0x1000)
    key = (K0 + K1 + BSS_RVA + seed - 1) & 0xFFFFFFFF
    prev = 0

    for off in range(0, 0x1000, 4):
        enc = u32(src, off)
        if enc == 0:
            break
        dec = (enc + prev - key) & 0xFFFFFFFF
        struct.pack_into('<I', dst, off, dec)
        prev = enc

    marker = 0x1A7 + seed
    checksum = (u32(dst, marker + 0x0C) - u32(dst, marker + 0x08) + u32(dst, marker + 0x04)) & 0xFFFFFFFF
    return bytes(dst[:BSS_SIZE]), key, marker, checksum

def strings(data, min_len=4):
    out = []
    start = None
    for i, c in enumerate(data + b'\x00'):
        if 32 <= c <= 126:
            if start is None:
                start = i
        else:
            if start is not None and i - start >= min_len:
                out.append((start, data[start:i].decode('latin1')))
            start = None
    return out

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('pe')
    ap.add_argument('-o', '--out', default='gozi_decoded.bin')
    args = ap.parse_args()

    pe = Path(args.pe).read_bytes()

    for seed in range(0x100):
        dec, key, marker, checksum = decode_bss(pe, seed)
        if checksum == CHECK:
            Path(args.out).write_bytes(dec)
            print(f'seed=0x{seed:x}')
            print(f'key=0x{key:08x}')
            print(f'marker_off=0x{marker:x}')
            print(f'checksum=0x{checksum:08x}')
            print(f'output={args.out}')
            print()
            for off, s in strings(dec):
                print(f'0x{off:04x}: {s}')
            return

    raise SystemExit('no valid seed found')

if __name__ == '__main__':
    main()
This post is licensed under CC BY 4.0 by the author.