├── README.md ├── pivy_config.py └── spynet26_find_config.py /README.md: -------------------------------------------------------------------------------- 1 | pycommands 2 | ========== 3 | 4 | PyCommand Scripts for Immunity Debugger 5 | -------------------------------------------------------------------------------- /pivy_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | import re 25 | import binascii 26 | import struct 27 | import string 28 | from immlib import * 29 | from immutils import * 30 | 31 | str_regex = r"^([\w\x20\x00\t\\\:\-\.\&\%\$\#\@\!\(\)\*]+)$" 32 | 33 | def main(args): 34 | imm = Debugger() 35 | regs = imm.getRegs() 36 | structaddr = regs["ESI"] 37 | if len(args) > 0: 38 | structaddr = int(args[0], 16) 39 | 40 | 41 | imm.log("PI struct address: 0x%08X" % structaddr) 42 | id = imm.readString(structaddr + int("AFA", 16)) 43 | group = imm.readString(structaddr + int("BF9", 16)) 44 | pw = imm.readMemory(structaddr + int("145", 16), 32) 45 | 46 | imm.log("ID: %s" % id) 47 | imm.log("Group: %s" % group) 48 | 49 | match = re.match(str_regex,pw) 50 | if match is not None: 51 | pw = string.strip(pw, "\x00") 52 | imm.log("Password: %s" % pw) 53 | else: 54 | imm.log("Password: 0x%s" % (binascii.hexlify(pw))) 55 | 56 | mutex = imm.readString(structaddr + int("3FB", 16)) 57 | imm.log("Mutex: %s" % mutex) 58 | proxy = False 59 | if imm.readShort(structaddr + int("2C1", 16)) == 1: 60 | proxy = True 61 | 62 | if proxy: 63 | cnt = 0 64 | C2offset = int("2C5", 16) 65 | while True: 66 | str_len = imm.readMemory(structaddr + C2offset + cnt, 1) 67 | cnt = cnt + 1 68 | str_len = struct.unpack('B', str_len)[0] 69 | domaindata = imm.readMemory(structaddr + C2offset + cnt, str_len) 70 | 71 | domain = "" 72 | for c in domaindata: 73 | if c != "\x00": 74 | domain += c 75 | else: 76 | break 77 | cnt = cnt + str_len 78 | imm.log("C2: %s" % domain) 79 | version = imm.readMemory(structaddr + C2offset + cnt, 1) 80 | cnt = cnt + 1 81 | version = struct.unpack('B', version)[0] 82 | imm.log("C2 version: %d" % version) 83 | port = imm.readShort(structaddr + C2offset + cnt) 84 | cnt = cnt + 2 85 | imm.log("C2 port: %d" % port) 86 | if struct.unpack('B', imm.readMemory(structaddr + C2offset + cnt, 1))[0] == 0: 87 | break 88 | imm.log("***********") 89 | 90 | cnt = 0 91 | C2offset = int("190", 16) 92 | while True: 93 | str_len = imm.readMemory(structaddr + C2offset + cnt, 1) 94 | cnt = cnt + 1 95 | str_len = struct.unpack('B', str_len)[0] 96 | domaindata = imm.readMemory(structaddr + C2offset + cnt, str_len) 97 | 98 | domain = "" 99 | for c in domaindata: 100 | if c != "\x00": 101 | domain += c 102 | else: 103 | break 104 | 105 | cnt = cnt + str_len 106 | if proxy is True: 107 | imm.log("Proxy: %s" % domain) 108 | else: 109 | imm.log("C2: %s" % domain) 110 | version = imm.readMemory(structaddr + C2offset + cnt, 1) 111 | cnt = cnt + 1 112 | version = struct.unpack('B', version)[0] 113 | if proxy is True: 114 | imm.log("Proxy version: %d" % version) 115 | else: 116 | imm.log("C2 version: %d" % version) 117 | port = imm.readShort(structaddr + C2offset + cnt) 118 | cnt = cnt + 2 119 | if proxy is True: 120 | imm.log("Proxy port: %d" % port) 121 | else: 122 | imm.log("C2 port: %d" % port) 123 | if struct.unpack('B', imm.readMemory(structaddr + C2offset + cnt, 1))[0] == 0: 124 | break 125 | imm.log("***********") 126 | 127 | implant = imm.readString(structaddr + int("12D", 16)) 128 | 129 | ads = imm.readMemory(structaddr + int("D12", 16), 1) 130 | ads = struct.unpack('B', ads)[0] 131 | 132 | copydir = struct.unpack('B', imm.readMemory(structaddr + int("3F7", 16), 1))[0] 133 | 134 | destination = "" 135 | if copydir == 1: 136 | destination = "%WINDIR%" 137 | elif copydir == 2: 138 | destination = "%WINDIR%\\system32" 139 | 140 | if ads == 1: 141 | destination += ':' 142 | elif destination != "": 143 | destination += '\\' 144 | 145 | if destination != "": 146 | implant = destination + implant 147 | imm.log("Implant filename: %s" % implant) 148 | 149 | activesetup = struct.unpack('B', imm.readMemory(structaddr + int("3F6", 16), 1))[0] 150 | if activesetup == 1: 151 | runkey = imm.readString(structaddr + int("4B3", 16)) 152 | runname = imm.readString(structaddr + int("40F", 16)) 153 | imm.log("Active Setup key: %s" % runkey) 154 | imm.log("Active Setup value name: %s" % runname) 155 | 156 | run = struct.unpack('B', imm.readMemory(structaddr + int("D09", 16), 1))[0] 157 | if run == 1: 158 | runname = imm.readString(structaddr + int("E12", 16)) 159 | imm.log("HKLM run value name: %s" % runname) 160 | 161 | keylogconf = imm.readMemory(structaddr + int("3FA", 16), 1) 162 | keylogconf = struct.unpack('B', keylogconf)[0] 163 | if keylogconf == 1: 164 | imm.log("Keylogger installed") 165 | 166 | if keylogconf == 1: 167 | keylog = imm.readString(structaddr + int("7B0", 16)) 168 | imm.log("Key stroke log file: %s" % keylog) 169 | 170 | return "Complete.." -------------------------------------------------------------------------------- /spynet26_find_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 FireEye, Inc. All rights reserved. 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 1. Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # 2. Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | # SUCH DAMAGE. 23 | 24 | 25 | from immlib import * 26 | from immutils import * 27 | import re 28 | import binascii 29 | import struct 30 | import string 31 | findconfig = r"\x55\x8b\xec\x6a\x00\x6a\x00\x6a\x00\x53\x56\x57\x8b\xd8\x8b\x3d(.{4})\x33\xc0\x55" 32 | c2ptn = r".+\..+:[\d]+" 33 | def main(args): 34 | imm = Debugger() 35 | configptr = None 36 | for page in imm.getMemoryPages(): 37 | if page.getSize() == 0x62000: 38 | imm.log("checking pages: %08X" % page.getBaseAddress()) 39 | mem = page.getMemory() 40 | match = re.search(findconfig,mem) 41 | if not match: 42 | continue 43 | ptr = struct.unpack('