[
  {
    "path": "README.txt",
    "content": "Welcome to IDA Sploiter, an exploit development and vulnerability research\nplugin for Hex-Ray's IDA Pro disassembler.\n\nTo install IDA Sploiter simply copy all the python files to IDA's plugins folder. \nThe plugin will be automatically loaded the next time you start IDA Pro.\n\nIDA Sploiter currently supports the following architectures:\n  - x86/amd64\n  - PowerPC\n\nYou can find the latest IDA Sploiter version and documentation here: \n    http://thesprawl.org/projects/ida-sploiter/\n\nHappy sploiting!\n  -Peter Kacherginsky <iphelix@thesprawl.org>\n"
  },
  {
    "path": "idasploiter.py",
    "content": "#!/usr/bin/env python\r\n#\r\n# IDA Sploiter is an exploit development and vulnerability research environment\r\n# implemented as a plugin for Hex-Ray's IDA Pro disassembler.\r\n\r\nIDASPLOITER_VERSION = \"1.1\"\r\n\r\n# Copyright (C) 2014 Peter Kacherginsky\r\n# All rights reserved.\r\n#\r\n# Redistribution and use in source and binary forms, with or without\r\n# modification, are permitted provided that the following conditions are met: \r\n#\r\n# 1. Redistributions of source code must retain the above copyright notice, this\r\n#    list of conditions and the following disclaimer. \r\n# 2. Redistributions in binary form must reproduce the above copyright notice,\r\n#    this list of conditions and the following disclaimer in the documentation\r\n#    and/or other materials provided with the distribution.\r\n# 3. Neither the name of the copyright holder nor the names of its contributors\r\n#    may be used to endorse or promote products derived from this software without \r\n#    specific prior written permission.\r\n#\r\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r\n# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n# Performance profiling\r\nimport cProfile\r\nimport pstats\r\n\r\n# IDA libraries\r\nimport idaapi\r\nimport idautils\r\nimport idc\r\nfrom idaapi import Form, Choose2, plugin_t\r\n\r\n# Python libraries\r\nimport os\r\nimport binascii\r\nimport string\r\nimport textwrap\r\nimport copy\r\nimport csv\r\nimport itertools\r\nimport struct\r\n\r\nfrom struct import pack, unpack\r\nfrom ctypes import *\r\n\r\n###############################################################################\r\n# Data Tables and Structures\r\n###############################################################################\r\n\r\n# Initialize the list of supported processors.\r\nSPLOITER_SUPPORTED_ARCHES = [\r\n    idaapi.PLFM_386,\r\n\tidaapi.PLFM_PPC\r\n]\r\n\r\n###############################################################################\r\n# 00-FF Single byte to unicode transforms\r\n# NOTE: Some unicode characters can have two bytes\r\n#       http://www.phenoelit.org/stuff/Phenoelit20c3.pdf\r\n\r\n# Ascii_to_Unicode_transforms\r\nASCII_TO_UNICODE_GENERAL = [\r\n    \"\\x00\\x00\", \"\\x00\\x01\", \"\\x00\\x02\", \"\\x00\\x03\", \"\\x00\\x04\", \"\\x00\\x05\",\r\n    \"\\x00\\x06\", \"\\x00\\x07\", \"\\x00\\x08\", \"\\x00\\x09\", \"\\x00\\x0a\", \"\\x00\\x0b\", \r\n    \"\\x00\\x0c\", \"\\x00\\x0d\", \"\\x00\\x0e\", \"\\x00\\x0f\", \"\\x00\\x10\", \"\\x00\\x11\", \r\n    \"\\x00\\x12\", \"\\x00\\x13\", \"\\x00\\x14\", \"\\x00\\x15\", \"\\x00\\x16\", \"\\x00\\x17\", \r\n    \"\\x00\\x18\", \"\\x00\\x19\", \"\\x00\\x1a\", \"\\x00\\x1b\", \"\\x00\\x1c\", \"\\x00\\x1d\", \r\n    \"\\x00\\x1e\", \"\\x00\\x1f\", \"\\x00\\x20\", \"\\x00\\x21\", \"\\x00\\x22\", \"\\x00\\x23\", \r\n    \"\\x00\\x24\", \"\\x00\\x25\", \"\\x00\\x26\", \"\\x00\\x27\", \"\\x00\\x28\", \"\\x00\\x29\", \r\n    \"\\x00\\x2a\", \"\\x00\\x2b\", \"\\x00\\x2c\", \"\\x00\\x2d\", \"\\x00\\x2e\", \"\\x00\\x2f\", \r\n    \"\\x00\\x30\", \"\\x00\\x31\", \"\\x00\\x32\", \"\\x00\\x33\", \"\\x00\\x34\", \"\\x00\\x35\", \r\n    \"\\x00\\x36\", \"\\x00\\x37\", \"\\x00\\x38\", \"\\x00\\x39\", \"\\x00\\x3a\", \"\\x00\\x3b\", \r\n    \"\\x00\\x3c\", \"\\x00\\x3d\", \"\\x00\\x3e\", \"\\x00\\x3f\", \"\\x00\\x40\", \"\\x00\\x41\", \r\n    \"\\x00\\x42\", \"\\x00\\x43\", \"\\x00\\x44\", \"\\x00\\x45\", \"\\x00\\x46\", \"\\x00\\x47\", \r\n    \"\\x00\\x48\", \"\\x00\\x49\", \"\\x00\\x4a\", \"\\x00\\x4b\", \"\\x00\\x4c\", \"\\x00\\x4d\", \r\n    \"\\x00\\x4e\", \"\\x00\\x4f\", \"\\x00\\x50\", \"\\x00\\x51\", \"\\x00\\x52\", \"\\x00\\x53\", \r\n    \"\\x00\\x54\", \"\\x00\\x55\", \"\\x00\\x56\", \"\\x00\\x57\", \"\\x00\\x58\", \"\\x00\\x59\", \r\n    \"\\x00\\x5a\", \"\\x00\\x5b\", \"\\x00\\x5c\", \"\\x00\\x5d\", \"\\x00\\x5e\", \"\\x00\\x5f\", \r\n    \"\\x00\\x60\", \"\\x00\\x61\", \"\\x00\\x62\", \"\\x00\\x63\", \"\\x00\\x64\", \"\\x00\\x65\", \r\n    \"\\x00\\x66\", \"\\x00\\x67\", \"\\x00\\x68\", \"\\x00\\x69\", \"\\x00\\x6a\", \"\\x00\\x6b\", \r\n    \"\\x00\\x6c\", \"\\x00\\x6d\", \"\\x00\\x6e\", \"\\x00\\x6f\", \"\\x00\\x70\", \"\\x00\\x71\", \r\n    \"\\x00\\x72\", \"\\x00\\x73\", \"\\x00\\x74\", \"\\x00\\x75\", \"\\x00\\x76\", \"\\x00\\x77\", \r\n    \"\\x00\\x78\", \"\\x00\\x79\", \"\\x00\\x7a\", \"\\x00\\x7b\", \"\\x00\\x7c\", \"\\x00\\x7d\", \r\n    \"\\x00\\x7e\", \"\\x00\\x7f\"\r\n]\r\n\r\nASCII_TO_UNICODE_ANSI = ASCII_TO_UNICODE_GENERAL + [\r\n    \"\\x20\\xac\", \"\\x00\\x81\", \"\\x20\\x1a\", \"\\x01\\x92\", \"\\x20\\x1e\", \"\\x20\\x26\",\r\n    \"\\x20\\x20\", \"\\x20\\x21\", \"\\x02\\xc6\", \"\\x20\\x30\", \"\\x01\\x60\", \"\\x20\\x39\",\r\n    \"\\x01\\x52\", \"\\x00\\x8d\", \"\\x01\\x7d\", \"\\x00\\x8f\", \"\\x90\\x00\", \"\\x20\\x18\",\r\n    \"\\x20\\x19\", \"\\x20\\x1c\", \"\\x20\\x1d\", \"\\x20\\x22\", \"\\x20\\x13\", \"\\x20\\x14\",\r\n    \"\\x02\\xdc\", \"\\x21\\x22\", \"\\x01\\x61\", \"\\x3a\\x20\", \"\\x01\\x53\", \"\\x00\\x9d\",\r\n    \"\\x01\\x7e\", \"\\x01\\x78\", \"\\x00\\xa0\", \"\\x00\\xa1\", \"\\x00\\xa2\", \"\\x00\\xa3\",\r\n    \"\\x00\\xa4\", \"\\x00\\xa5\", \"\\x00\\xa6\", \"\\x00\\xa7\", \"\\x00\\xa8\", \"\\x00\\xa9\",\r\n    \"\\x00\\xaa\", \"\\x00\\xab\", \"\\x00\\xac\", \"\\x00\\xad\", \"\\x00\\xae\", \"\\x00\\xaf\",\r\n    \"\\x00\\xb0\", \"\\x00\\xb1\", \"\\x00\\xb2\", \"\\x00\\xb3\", \"\\x00\\xb4\", \"\\x00\\xb5\",\r\n    \"\\x00\\xb6\", \"\\x00\\xb7\", \"\\x00\\xb8\", \"\\x00\\xb9\", \"\\x00\\xba\", \"\\x00\\xbb\",\r\n    \"\\x00\\xbc\", \"\\x00\\xbd\", \"\\x00\\xbe\", \"\\x00\\xbf\", \"\\x00\\xc0\", \"\\x00\\xc1\",\r\n    \"\\x00\\xc2\", \"\\x00\\xc3\", \"\\x00\\xc4\", \"\\x00\\xc5\", \"\\x00\\xc6\", \"\\x00\\xc7\",\r\n    \"\\x00\\xc8\", \"\\x00\\xc9\", \"\\x00\\xca\", \"\\x00\\xcb\", \"\\x00\\xcc\", \"\\x00\\xcd\",\r\n    \"\\x00\\xce\", \"\\x00\\xcf\", \"\\x00\\xd0\", \"\\x00\\xd1\", \"\\x00\\xd2\", \"\\x00\\xd3\",\r\n    \"\\x00\\xd4\", \"\\x00\\xd5\", \"\\x00\\xd6\", \"\\x00\\xd7\", \"\\x00\\xd8\", \"\\x00\\xd9\",\r\n    \"\\x00\\xda\", \"\\x00\\xdb\", \"\\x00\\xdc\", \"\\x00\\xdd\", \"\\x00\\xde\", \"\\x00\\xdf\",\r\n    \"\\x00\\xe0\", \"\\x00\\xe1\", \"\\x00\\xe2\", \"\\x00\\xe3\", \"\\x00\\xe4\", \"\\x00\\xe5\",\r\n    \"\\x00\\xe6\", \"\\x00\\xe7\", \"\\x00\\xe8\", \"\\x00\\xe9\", \"\\x00\\xea\", \"\\x00\\xeb\",\r\n    \"\\x00\\xec\", \"\\x00\\xed\", \"\\x00\\xee\", \"\\x00\\xef\", \"\\x00\\xf0\", \"\\x00\\xf1\",\r\n    \"\\x00\\xf2\", \"\\x00\\xf3\", \"\\x00\\xf4\", \"\\x00\\xf5\", \"\\x00\\xf6\", \"\\x00\\xf7\",\r\n    \"\\x00\\xf8\", \"\\x00\\xf9\", \"\\x00\\xfa\", \"\\x00\\xfb\", \"\\x00\\xfc\", \"\\x00\\xfd\",\r\n    \"\\x00\\xfe\", \"\\x00\\xff\"\r\n]\r\n\r\nASCII_TO_UNICODE_OEM = ASCII_TO_UNICODE_GENERAL + [\r\n    \"\\x00\\xc7\", \"\\x00\\xfc\", \"\\x00\\xe9\", \"\\x00\\xe2\", \"\\x00\\xe4\", \"\\x00\\xe0\",\r\n    \"\\x00\\xe5\", \"\\x00\\xe7\", \"\\x00\\xea\", \"\\x00\\xeb\", \"\\x00\\xe8\", \"\\x00\\xef\",\r\n    \"\\x00\\xee\", \"\\x00\\xec\", \"\\x00\\xc4\", \"\\x00\\xc5\", \"\\x00\\xc9\", \"\\x00\\xe6\",\r\n    \"\\x00\\xc6\", \"\\x00\\xf4\", \"\\x00\\xf6\", \"\\x00\\xf2\", \"\\x00\\xfb\", \"\\x00\\xf9\",\r\n    \"\\x00\\xff\", \"\\x00\\xd6\", \"\\x00\\xdc\", \"\\x00\\xf8\", \"\\x00\\xa3\", \"\\x00\\xd8\",\r\n    \"\\x00\\xd7\", \"\\x01\\x92\", \"\\x00\\xe1\", \"\\x00\\xed\", \"\\x00\\xf3\", \"\\x00\\xfa\",\r\n    \"\\x00\\xf1\", \"\\x00\\xd1\", \"\\x00\\xaa\", \"\\x00\\xba\", \"\\x00\\xbf\", \"\\x00\\xae\",\r\n    \"\\x00\\xac\", \"\\x00\\xbd\", \"\\x00\\xbc\", \"\\x00\\xa1\", \"\\x00\\xab\", \"\\x00\\xbb\",\r\n    \"\\x25\\x91\", \"\\x25\\x92\", \"\\x25\\x93\", \"\\x25\\x02\", \"\\x25\\x24\", \"\\x00\\xc1\",\r\n    \"\\x00\\xc2\", \"\\x00\\xc0\", \"\\x00\\xa9\", \"\\x25\\x63\", \"\\x25\\x51\", \"\\x25\\x57\",\r\n    \"\\x25\\x5d\", \"\\x00\\xa2\", \"\\x00\\xa5\", \"\\x25\\x10\", \"\\x25\\x14\", \"\\x25\\x34\",\r\n    \"\\x25\\x2c\", \"\\x25\\x1c\", \"\\x25\\x00\", \"\\x25\\x3c\", \"\\x00\\xe3\", \"\\x00\\xc3\",\r\n    \"\\x25\\x5a\", \"\\x25\\x54\", \"\\x25\\x69\", \"\\x25\\x66\", \"\\x25\\x60\", \"\\x25\\x50\",\r\n    \"\\x25\\x6c\", \"\\x00\\xa4\", \"\\x00\\xf0\", \"\\x00\\xd0\", \"\\x00\\xca\", \"\\x00\\xcb\",\r\n    \"\\x00\\xc8\", \"\\x01\\x31\", \"\\x00\\xcd\", \"\\x00\\xce\", \"\\x00\\xcf\", \"\\x25\\x18\",\r\n    \"\\x25\\x0c\", \"\\x25\\x88\", \"\\x25\\x84\", \"\\x00\\xa6\", \"\\x00\\xcc\", \"\\x25\\x80\",\r\n    \"\\x00\\xd3\", \"\\x00\\xdf\", \"\\x00\\xd4\", \"\\x00\\xd2\", \"\\x00\\xf5\", \"\\x00\\xd5\",\r\n    \"\\x00\\xb5\", \"\\x00\\xfe\", \"\\x00\\xde\", \"\\x00\\xda\", \"\\x00\\xdb\", \"\\x00\\xd9\",\r\n    \"\\x00\\xfd\", \"\\x00\\xdd\", \"\\x00\\xaf\", \"\\x00\\xb4\", \"\\x00\\xad\", \"\\x00\\xb1\",\r\n    \"\\x20\\x17\", \"\\x00\\xbe\", \"\\x00\\xb6\", \"\\x00\\xa7\", \"\\x00\\xf7\", \"\\x00\\xb8\",\r\n    \"\\x00\\xb0\", \"\\x00\\xa8\", \"\\x00\\xb7\", \"\\x00\\xb9\", \"\\x00\\xb3\", \"\\x00\\xb2\",\r\n    \"\\x25\\xa0\", \"\\x00\\xa0\"\r\n]\r\n\r\nASCII_TO_UNICODE_UTF7 = ASCII_TO_UNICODE_GENERAL + [\r\n    \"\\xff\\x80\", \"\\xff\\x81\", \"\\xff\\x82\", \"\\xff\\x83\", \"\\xff\\x84\", \"\\xff\\x85\",\r\n    \"\\xff\\x86\", \"\\xff\\x87\", \"\\xff\\x88\", \"\\xff\\x89\", \"\\xff\\x8a\", \"\\xff\\x8b\",\r\n    \"\\xff\\x8c\", \"\\xff\\x8d\", \"\\xff\\x8e\", \"\\xff\\x8f\", \"\\xff\\x90\", \"\\xff\\x91\",\r\n    \"\\xff\\x92\", \"\\xff\\x93\", \"\\xff\\x94\", \"\\xff\\x95\", \"\\xff\\x96\", \"\\xff\\x97\",\r\n    \"\\xff\\x98\", \"\\xff\\x99\", \"\\xff\\x9a\", \"\\xff\\x9b\", \"\\xff\\x9c\", \"\\xff\\x9d\",\r\n    \"\\xff\\x9e\", \"\\xff\\x9f\", \"\\xff\\xa0\", \"\\xff\\xa1\", \"\\xff\\xa2\", \"\\xff\\xa3\",\r\n    \"\\xff\\xa4\", \"\\xff\\xa5\", \"\\xff\\xa6\", \"\\xff\\xa7\", \"\\xff\\xa8\", \"\\xff\\xa9\",\r\n    \"\\xff\\xaa\", \"\\xff\\xab\", \"\\xff\\xac\", \"\\xff\\xad\", \"\\xff\\xae\", \"\\xff\\xaf\",\r\n    \"\\xff\\xb0\", \"\\xff\\xb1\", \"\\xff\\xb2\", \"\\xff\\xb3\", \"\\xff\\xb4\", \"\\xff\\xb5\",\r\n    \"\\xff\\xb6\", \"\\xff\\xb7\", \"\\xff\\xb8\", \"\\xff\\xb9\", \"\\xff\\xba\", \"\\xff\\xbb\",\r\n    \"\\xff\\xbc\", \"\\xff\\xbd\", \"\\xff\\xbe\", \"\\xff\\xbf\", \"\\xff\\xc0\", \"\\xff\\xc1\",\r\n    \"\\xff\\xc2\", \"\\xff\\xc3\", \"\\xff\\xc4\", \"\\xff\\xc5\", \"\\xff\\xc6\", \"\\xff\\xc7\",\r\n    \"\\xff\\xc8\", \"\\xff\\xc9\", \"\\xff\\xca\", \"\\xff\\xcb\", \"\\xff\\xcc\", \"\\xff\\xcd\",\r\n    \"\\xff\\xce\", \"\\xff\\xcf\", \"\\xff\\xd0\", \"\\xff\\xd1\", \"\\xff\\xd2\", \"\\xff\\xd3\",\r\n    \"\\xff\\xd4\", \"\\xff\\xd5\", \"\\xff\\xd6\", \"\\xff\\xd7\", \"\\xff\\xd8\", \"\\xff\\xd9\",\r\n    \"\\xff\\xda\", \"\\xff\\xdb\", \"\\xff\\xdc\", \"\\xff\\xdd\", \"\\xff\\xde\", \"\\xff\\xdf\",\r\n    \"\\xff\\xe0\", \"\\xff\\xe1\", \"\\xff\\xe2\", \"\\xff\\xe3\", \"\\xff\\xe4\", \"\\xff\\xe5\",\r\n    \"\\xff\\xe6\", \"\\xff\\xe7\", \"\\xff\\xe8\", \"\\xff\\xe9\", \"\\xff\\xea\", \"\\xff\\xeb\",\r\n    \"\\xff\\xec\", \"\\xff\\xed\", \"\\xff\\xee\", \"\\xff\\xef\", \"\\xff\\xf0\", \"\\xff\\xf1\",\r\n    \"\\xff\\xf2\", \"\\xff\\xf3\", \"\\xff\\xf4\", \"\\xff\\xf5\", \"\\xff\\xf6\", \"\\xff\\xf7\",\r\n    \"\\xff\\xf8\", \"\\xff\\xf9\", \"\\xff\\xfa\", \"\\xff\\xfb\", \"\\xff\\xfc\", \"\\xff\\xfd\",\r\n    \"\\xff\\xfe\", \"\\xff\\xff\"\r\n]\r\n\r\nASCII_TO_UNICODE_UTF8 = ASCII_TO_UNICODE_GENERAL + [\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\",\r\n    \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x00\", \"\\x00\\x01\",\r\n    \"\\x00\\x02\", \"\\x00\\x03\", \"\\x00\\x04\", \"\\x00\\x05\", \"\\x00\\x06\", \"\\x00\\x07\",\r\n    \"\\x00\\x08\", \"\\x00\\x09\", \"\\x00\\x0a\", \"\\x00\\x0b\", \"\\x00\\x0c\", \"\\x00\\x0d\",\r\n    \"\\x00\\x0e\", \"\\x00\\x0f\", \"\\x00\\x10\", \"\\x00\\x11\", \"\\x00\\x12\", \"\\x00\\x13\",\r\n    \"\\x00\\x14\", \"\\x00\\x15\", \"\\x00\\x16\", \"\\x00\\x17\", \"\\x00\\x18\", \"\\x00\\x19\",\r\n    \"\\x00\\x1a\", \"\\x00\\x1b\", \"\\x00\\x1c\", \"\\x00\\x1d\", \"\\x00\\x1e\", \"\\x00\\x1f\",\r\n    \"\\x00\\x00\", \"\\x00\\x01\", \"\\x00\\x02\", \"\\x00\\x03\", \"\\x00\\x04\", \"\\x00\\x05\",\r\n    \"\\x00\\x06\", \"\\x00\\x07\", \"\\x00\\x08\", \"\\x00\\x09\", \"\\x00\\x0a\", \"\\x00\\x0b\",\r\n    \"\\x00\\x0c\", \"\\x00\\x0d\", \"\\x00\\x0e\", \"\\x00\\x0f\", \"\\x00\\x00\", \"\\x00\\x01\",\r\n    \"\\x00\\x02\", \"\\x00\\x03\", \"\\x00\\x04\", \"\\x00\\x05\", \"\\x00\\x06\", \"\\x00\\x07\",\r\n    \"\\x00\\x08\", \"\\x00\\x09\", \"\\x00\\x0a\", \"\\x00\\x0b\", \"\\x00\\x0c\", \"\\x00\\x0d\",\r\n    \"\\x00\\x0e\", \"\\x00\\x0f\"\r\n]\r\n\r\nASCII_TO_UNICODE = [ASCII_TO_UNICODE_ANSI,\r\n                    ASCII_TO_UNICODE_OEM, \r\n                    ASCII_TO_UNICODE_UTF7, \r\n                    ASCII_TO_UNICODE_UTF8]\r\n\r\n###############################################################################\r\n# Microsoft Portable Executable and Common Object File Format Specification\r\n# Revision 8.3 - February 6, 2013\r\n\r\nclass IMAGE_DOS_HEADER(Structure):\r\n    _fields_ = [\r\n                    (\"signature\" , c_char * 2),\r\n                    (\"lastsize\"  , c_short),\r\n                    (\"nblocks\"   , c_short),\r\n                    (\"nreloc\"    , c_short),\r\n                    (\"hdrsize\"   , c_short),\r\n                    (\"minalloc\"  , c_short),\r\n                    (\"maxalloc\"  , c_short),\r\n                    (\"ss\"        , c_short),\r\n                    (\"sp\"        , c_short),\r\n                    (\"checksum\"  , c_short),\r\n                    (\"ip\"        , c_short),\r\n                    (\"cs\"        , c_short),\r\n                    (\"relocpos\"  , c_short),\r\n                    (\"noverlay\"  , c_short),\r\n                    (\"reserved1\" , c_short * 4),\r\n                    (\"oem_id\"    , c_short),\r\n                    (\"reserved2\" , c_short * 10),\r\n                    (\"e_lfanew\"  , c_long)\r\n                ]\r\n\r\nclass IMAGE_FILE_HEADER(Structure):\r\n    _fields_ = [\r\n                    (\"Machine\"              , c_short),\r\n                    (\"NumberOfSections\"     , c_short),\r\n                    (\"TimeDateStamp\"        , c_long),\r\n                    (\"PointerToSymbolTable\" , c_long),\r\n                    (\"NumberOfSymbols\"      , c_long),\r\n                    (\"SizeOfOptionalHeader\" , c_short),\r\n                    (\"Characteristics\"      , c_short)\r\n                ]\r\n\r\nclass IMAGE_DATA_DIRECTORY(Structure):\r\n    _fields_ = [\r\n                    (\"VirtualAddress\", c_long),\r\n                    (\"Size\", c_long)\r\n                ]\r\n\r\nclass IMAGE_OPTIONAL_HEADER(Structure):\r\n    _fields_ = [\r\n                    (\"signature\"               , c_short),\r\n                    (\"MajorLinkerVersion\"      , c_byte),\r\n                    (\"MinorLinkerVersion\"      , c_byte),\r\n                    (\"SizeOfCode\"              , c_long),\r\n                    (\"SizeOfInitializedData\"   , c_long),\r\n                    (\"SizeOfUninitializedData\" , c_long),\r\n                    (\"AddressOfEntryPoint\"     , c_long),\r\n                    (\"BaseOfCode\"              , c_long),\r\n                    (\"BaseOfData\"              , c_long),\r\n                    (\"ImageBase\"               , c_long),\r\n                    (\"SectionAlignment\"        , c_long),\r\n                    (\"FileAlignment\"           , c_long),\r\n                    (\"MajorOSVersion\"          , c_short),\r\n                    (\"MinorOSVersion\"          , c_short),\r\n                    (\"MajorImageVersion\"       , c_short),\r\n                    (\"MinorImageVersion\"       , c_short),\r\n                    (\"MajorSubsystemVersion\"   , c_short),\r\n                    (\"MinorSubsystemVersion\"   , c_short),\r\n                    (\"Reserved\"                , c_long),\r\n                    (\"SizeOfImage\"             , c_long),\r\n                    (\"SizeOfHeaders\"           , c_long),\r\n                    (\"Checksum\"                , c_long),\r\n                    (\"Subsystem\"               , c_short),\r\n                    (\"DLLCharacteristics\"      , c_short),\r\n                    (\"SizeOfStackReserve\"      , c_long),\r\n                    (\"SizeOfStackCommit\"       , c_long),\r\n                    (\"SizeOfHeapReserve\"       , c_long),\r\n                    (\"SizeOfHeapCommit\"        , c_long),\r\n                    (\"LoaderFlags\"             , c_long),\r\n                    (\"NumberOfRvaAndSizes\"     , c_long),\r\n                    (\"DataDirectory\"           , IMAGE_DATA_DIRECTORY * 16)\r\n                ]\r\n\r\nclass IMAGE_OPTIONAL_HEADER64(Structure):\r\n    _fields_ = [\r\n                    (\"signature\"               , c_short),\r\n                    (\"MajorLinkerVersion\"      , c_byte),\r\n                    (\"MinorLinkerVersion\"      , c_byte),\r\n                    (\"SizeOfCode\"              , c_long),\r\n                    (\"SizeOfInitializedData\"   , c_long),\r\n                    (\"SizeOfUninitializedData\" , c_long),\r\n                    (\"AddressOfEntryPoint\"     , c_long),\r\n                    (\"BaseOfCode\"              , c_long),\r\n                    (\"ImageBase\"               , c_longlong),\r\n                    (\"SectionAlignment\"        , c_long),\r\n                    (\"FileAlignment\"           , c_long),\r\n                    (\"MajorOSVersion\"          , c_short),\r\n                    (\"MinorOSVersion\"          , c_short),\r\n                    (\"MajorImageVersion\"       , c_short),\r\n                    (\"MinorImageVersion\"       , c_short),\r\n                    (\"MajorSubsystemVersion\"   , c_short),\r\n                    (\"MinorSubsystemVersion\"   , c_short),\r\n                    (\"Reserved\"                , c_long),\r\n                    (\"SizeOfImage\"             , c_long),\r\n                    (\"SizeOfHeaders\"           , c_long),\r\n                    (\"Checksum\"                , c_long),\r\n                    (\"Subsystem\"               , c_short),\r\n                    (\"DLLCharacteristics\"      , c_short),\r\n                    (\"SizeOfStackReserve\"      , c_longlong),\r\n                    (\"SizeOfStackCommit\"       , c_longlong),\r\n                    (\"SizeOfHeapReserve\"       , c_longlong),\r\n                    (\"SizeOfHeapCommit\"        , c_longlong),\r\n                    (\"LoaderFlags\"             , c_long),\r\n                    (\"NumberOfRvaAndSizes\"     , c_long),\r\n                    (\"DataDirectory\"           , IMAGE_DATA_DIRECTORY * 16)\r\n                ]\r\n\r\nclass IMAGE_LOAD_CONFIG_DIRECTORY(Structure):\r\n    _fields_ = [\r\n                    (\"Size\"                          , c_long),\r\n                    (\"TimeDateStamp\"                 , c_long),\r\n                    (\"MajorVersion\"                  , c_short),\r\n                    (\"MinorVersion\"                  , c_short),\r\n                    (\"GlobalFlagsClear\"              , c_long),\r\n                    (\"GlobalFlagsSet\"                , c_long),\r\n                    (\"CriticalSectionDefaultTimeout\" , c_long),\r\n                    (\"DeCommitFreeBlockThreshold\"    , c_long),\r\n                    (\"DeCommitTotalFreeThreshold\"    , c_long),\r\n                    (\"LockPrefixTable\"               , c_long),\r\n                    (\"MaximumAllocationSize\"         , c_long),\r\n                    (\"VirtualMemoryThreshold\"        , c_long),\r\n                    (\"ProcessHeapFlags\"              , c_long),\r\n                    (\"ProcessAffinityMask\"           , c_long),\r\n                    (\"CSDVersion\"                    , c_short),\r\n                    (\"Reserved1\"                     , c_short),\r\n                    (\"EditList\"                      , c_long),\r\n                    (\"SecurityCookie\"                , c_long),\r\n                    (\"SEHandlerTable\"                , c_long),\r\n                    (\"SEHandlerCount\"                , c_long)\r\n                ]\r\n\r\nclass IMAGE_LOAD_CONFIG_DIRECTORY64(Structure):\r\n    _fields_ = [\r\n                    (\"Size\"                          , c_long),\r\n                    (\"TimeDateStamp\"                 , c_long),\r\n                    (\"MajorVersion\"                  , c_short),\r\n                    (\"MinorVersion\"                  , c_short),\r\n                    (\"GlobalFlagsClear\"              , c_long),\r\n                    (\"GlobalFlagsSet\"                , c_long),\r\n                    (\"CriticalSectionDefaultTimeout\" , c_long),\r\n                    (\"DeCommitFreeBlockThreshold\"    , c_longlong),\r\n                    (\"DeCommitTotalFreeThreshold\"    , c_longlong),\r\n                    (\"LockPrefixTable\"               , c_longlong),\r\n                    (\"MaximumAllocationSize\"         , c_longlong),\r\n                    (\"VirtualMemoryThreshold\"        , c_longlong),\r\n                    (\"ProcessHeapFlags\"              , c_long),\r\n                    (\"ProcessAffinityMask\"           , c_long),\r\n                    (\"CSDVersion\"                    , c_short),\r\n                    (\"Reserved1\"                     , c_short),\r\n                    (\"EditList\"                      , c_longlong),\r\n                    (\"SecurityCookie\"                , c_longlong),\r\n                    (\"SEHandlerTable\"                , c_longlong),\r\n                    (\"SEHandlerCount\"                , c_longlong),\r\n                ]\r\n\r\n\r\ndef is_processor_supported():\r\n    # Check if the current processor is supported.\r\n    if idaapi.ph.id not in SPLOITER_SUPPORTED_ARCHES:\r\n        return False\r\n    else:\r\n        return True\r\n\r\ndef read_module_memory(addr, size):\r\n    # Determine if the debugger is running and loaded.\r\n    if idaapi.dbg_can_query() and idaapi.get_process_state() < 0:\r\n        return idaapi.dbg_read_memory(addr, size)\r\n    else:\r\n        return idaapi.get_many_bytes(addr, size)\r\n\r\n###############################################################################\r\n# Module Class - Manages module characteristics\r\n\r\nclass Module():\r\n\r\n    def __init__(self, name, size, base, rebase_to):\r\n\r\n            self.addr = base\r\n\r\n            # BUG: IDA's API does not always zero out the SWIG buffer.\r\n            # BUG: ntdll does not have path information.\r\n            if \"\\x00\" in name:\r\n                name,junk = name.split(\"\\x00\",1)\r\n\r\n            self.file = os.path.basename(name)\r\n            self.path = os.path.dirname(name)\r\n\r\n            self.size = size\r\n\r\n            # Parse the module as a PE file\r\n            if idaapi.dbg_can_query() and idaapi.get_process_state() < 0:\r\n                pe = PE(self.addr)\r\n            else:\r\n                pe = None\r\n\r\n                self.NXCompat = \"No\"\r\n                self.ASLR = \"No\"\r\n                self.SafeSEH = \"N/A\"\r\n                self.GS = \"Null\"\r\n\r\n            if pe:\r\n                self.NXCompat = pe.isNXCompat()\r\n                self.ASLR     = pe.isDynamicBase()\r\n                self.SafeSEH  = pe.isSafeSEH()\r\n                self.GS       = pe.isGS()\r\n\r\n###############################################################################\r\n# PE Module Parser\r\n\r\nclass PE():\r\n\r\n    # PE flags\r\n    IMAGE_FILE_MACHINE_I386 = 0x14c\r\n\r\n    MAGIC_PE32      = 0x10b\r\n    MAGIC_PE32_PLUS = 0x20b\r\n\r\n    IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040\r\n    IMAGE_DLL_CHARACTERISTICS_NX_COMPAT    = 0x0100\r\n    IMAGE_DLLCHARACTERISTICS_NO_SEH        = 0x0400\r\n\r\n    def __init__(self, base):\r\n\r\n        # PE headers\r\n        self.dos_header            = None\r\n        self.file_header           = None\r\n        self.optional_header       = None\r\n        self.load_config_directory = None\r\n        self.arch64                = False\r\n\r\n        # Verify DOS header magic\r\n        magic_dos = read_module_memory( base, 0x2)\r\n        if magic_dos != \"MZ\":\r\n            print \"[idasploiter] Invalid DOS header magic.\"\r\n            return None\r\n\r\n        # Parse the DOS header\r\n        self.dos_header = IMAGE_DOS_HEADER.from_buffer_copy(\r\n            read_module_memory(base, 0x40) )\r\n\r\n        # Get offset to PE header\r\n        base_pe = base + self.dos_header.e_lfanew\r\n\r\n        # Verify PE header magic\r\n        magic_pe = read_module_memory( base_pe, 0x4 )\r\n        if magic_pe != \"PE\\x00\\x00\":\r\n            print \"[idasploiter] Invalid PE header magic: %x\" % unpack(\"I\",magic_pe)[0]\r\n            return None\r\n\r\n        # Parse the FILE header\r\n        # NOTE: IMAGE_FILE_HEADER size is 0x14\r\n        self.file_header = IMAGE_FILE_HEADER.from_buffer_copy( \r\n            read_module_memory( base_pe + 0x4, sizeof(IMAGE_FILE_HEADER) ) )\r\n\r\n        # Parse the OPTIONAL header\r\n        base_pe_optional =  base_pe + 0x4 + 0x14\r\n        magic_pe_opt = read_module_memory ( base_pe_optional, 0x2)\r\n        magic_pe_opt = unpack(\"H\", magic_pe_opt)[0]\r\n\r\n        # PE32 Optional Header\r\n        if magic_pe_opt == self.MAGIC_PE32:\r\n            self.arch64 = False\r\n            self.optional_header = IMAGE_OPTIONAL_HEADER.from_buffer_copy(\r\n                read_module_memory( base_pe_optional, self.file_header.SizeOfOptionalHeader ))\r\n\r\n        # PE32+ Optional Header\r\n        elif magic_pe_opt == self.MAGIC_PE32_PLUS:\r\n            self.arch64 = True\r\n            self.optional_header = IMAGE_OPTIONAL_HEADER64.from_buffer_copy(\r\n                read_module_memory( base_pe_optional, self.file_header.SizeOfOptionalHeader ))\r\n\r\n        # Invalid PE Header\r\n        else:\r\n            print \"[idasploiter] Invalid IMAGE_OPTIONAL_HEADER magic: %x\" % unpack(\"H\",magic_pe_opt)[0]\r\n            return None\r\n\r\n        # Load Configuration Table\r\n        load_config_directory_rva = self.optional_header.DataDirectory[10].VirtualAddress\r\n\r\n        # Parse Load Configuration Table if present\r\n        if load_config_directory_rva:\r\n\r\n            # Read LOAD CONFIG DIRECTORY size before parsing it\r\n            load_config_directory_size = read_module_memory( base + load_config_directory_rva, 0x4)\r\n            load_config_directory_size = unpack(\"I\",load_config_directory_size)[0]\r\n\r\n            # Parse LOAD CONFIG DIRECTORY based on PE32 format\r\n            if self.optional_header.signature == self.MAGIC_PE32:\r\n                self.load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORY.from_buffer_copy( read_module_memory( base + load_config_directory_rva, load_config_directory_size ))\r\n\r\n            # Parse LOAD CONFIG DIRECTORY based on PE32+ format\r\n            elif self.optional_header.signature == self.MAGIC_PE32_PLUS:\r\n                self.load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORY64.from_buffer_copy( read_module_memory( base + load_config_directory_rva, load_config_directory_size ))\r\n\r\n            # Invalid PE header\r\n            else:\r\n                print \"[idasploiter] Invalid IMAGE_OPTIONAL_HEADER magic: %x\" % unpack(\"H\",magic)[0]\r\n                return None\r\n\r\n    def isDynamicBase(self):\r\n        if self.optional_header:\r\n            if self.optional_header.DLLCharacteristics & self.IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE:\r\n                return \"Yes\"\r\n            else:\r\n                return \"No\"\r\n        else:\r\n            return \"Unk\"\r\n\r\n    def isNXCompat(self):\r\n        if self.optional_header:\r\n            if self.optional_header.DLLCharacteristics & self.IMAGE_DLL_CHARACTERISTICS_NX_COMPAT:\r\n                return \"Yes\"\r\n            else:\r\n                return \"No\"\r\n        else:\r\n            return \"Unk\"\r\n\r\n    def isSafeSEH(self):\r\n\r\n        if self.file_header and self.optional_header:\r\n\r\n            # SafeSEH is only applicable to 32-bit Windows.\r\n            if self.file_header.Machine != self.IMAGE_FILE_MACHINE_I386:\r\n                return \"N/A\"\r\n\r\n            # NO_SEH flag indicates that the module does not use SEH and no handlers can be called in this image.\r\n            elif self.optional_header.DLLCharacteristics & self.IMAGE_DLLCHARACTERISTICS_NO_SEH:\r\n                return \"No SEH\"\r\n\r\n            # SafeSEH is enabled when there is SEHandlerTable entry in the LOAD_CONFIG_DIRECTORY\r\n            elif self.load_config_directory and self.load_config_directory.SEHandlerTable != 0:\r\n                return \"Yes\"\r\n\r\n            # Otherwise SafeSEH is not used\r\n            else:\r\n                return \"No\"\r\n\r\n        else:\r\n            return \"Unk\"\r\n\r\n    def isGS(self):\r\n\r\n        if self.file_header and self.optional_header:\r\n\r\n            # NOTE: PE32+ does not necessarily provide a pointer to the Security Cookie in the\r\n            #       LoadConfigDirectory. The address appears to be still present in the binary.\r\n\r\n            # TODO: Need to do additional research into reliably detecting /GS in PE32+ files.\r\n\r\n            # PE32+ binaries with missing LoadConfigDirectory may still used security cookies.\r\n            if self.arch64 and not self.load_config_directory:\r\n                return \"Unk\"\r\n\r\n            if self.load_config_directory and self.load_config_directory.SecurityCookie != 0:\r\n\r\n                # Attempt to read the security cookie\r\n                # NOTE: The extra exception handler was added to account for cookie being stored in memory locations\r\n                #       that are not accessible by the debugger (e.g. manually loading win32k.sys, security cookie\r\n                #       address will point to kernel space which we can't read)\r\n                try:\r\n                    # Confirm the Security Cookie is not zero\r\n                    if self.arch64:\r\n                        cookie = read_module_memory(self.load_config_directory.SecurityCookie, 8)\r\n                        cookie = struct.unpack(\"<Q\", cookie)[0]\r\n                    else:\r\n                        cookie = read_module_memory(self.load_config_directory.SecurityCookie, 4)\r\n                        cookie = struct.unpack(\"<I\", cookie)[0]\r\n\r\n                    if cookie != 0:\r\n                        return \"Yes\"\r\n                    else:\r\n                        return \"Null\"\r\n\r\n                except Exception, e:\r\n                    return \"Inv\"\r\n\r\n            else:\r\n                return \"No\"\r\n\r\n        else:\r\n            return \"Unk\"\r\n\r\n###############################################################################\r\n# Pointer Class - Manager writable pointer characteristics\r\n\r\nclass Ptr():\r\n\r\n    def __init__(self, module, ptr_ea, ptr_offset, ptr_charset, call_ea, insn_disas):\r\n        self.module = module\r\n\r\n        self.ptr_ea = ptr_ea\r\n        self.ptr_offset = ptr_offset\r\n        self.ptr_charset = ptr_charset\r\n\r\n        self.call_ea = call_ea\r\n        self.insn_disas = insn_disas\r\n\r\n        self.name = idaapi.get_name(self.call_ea + self.ptr_offset, self.ptr_ea) or \"\"\r\n        self.call_name = idaapi.get_func_name(self.call_ea) or \"\"\r\n\r\n        self.p2p_ea = None\r\n        self.p2p_offset = None\r\n        self.p2p_charset = None\r\n\r\n###############################################################################\r\n# Function Pointer Search Engine\r\n\r\nclass FuncPtr():\r\n\r\n    def __init__(self,sploiter):\r\n\r\n        self.sploiter   = sploiter\r\n        self.ptr_calls  = list()\r\n        self.ptrs       = list()\r\n\r\n\r\n    def search_pointers(self):\r\n        # To be defined by parent classes.\r\n        pass\r\n\r\n###############################################################################\r\n# Gadget Class - manages ROP gadget characteristics\r\n\r\nclass Gadget():\r\n\r\n    def __init__(self, instructions, pivot, operations, chg_registers, use_registers):\r\n\r\n        self.address = 0x0\r\n\r\n        self.module = \"\"\r\n\r\n        self.instructions = instructions\r\n        self.size = len(instructions)\r\n\r\n        self.pivot = pivot\r\n        self.operations = operations\r\n\r\n        self.chg_registers = chg_registers\r\n        self.use_registers = use_registers\r\n\r\n        self.ptr_charset = []\r\n\r\n###############################################################################\r\n# ROP Search Engine\r\n\r\nclass Rop():\r\n\r\n    def __init__(self, sploiter):\r\n\r\n        self.maxRopOffset = 40 # Maximum offset from the return instruction to look for gadgets. default: 40\r\n        self.maxRopSize   = 6  # Maximum number of instructions to look for gadgets. default: 6\r\n        self.maxRetnImm   = 64 # Maximum imm16 value in retn. default: 64\r\n        self.maxJopImm    = 255 # Maximum jop [reg + IMM] value. default: 64\r\n        self.maxRops      = 0  # Maximum number of ROP chains to find. default: 0 (unlimited)\r\n\r\n        self.debug        = False\r\n\r\n        self.regnames     = idaapi.ph_get_regnames()\r\n\r\n        self.sploiter     = sploiter\r\n        self.retns        = list()\r\n        self.gadgets      = list()\r\n\r\n        # Decoded instruction cache\r\n        self.insn_cache = dict()\r\n\r\n    def get_o_reg_name(self, insn, n):\r\n\r\n        # To be defined by parent classes.\r\n        return None\r\n\r\n    def search_retns(self):\r\n\r\n        # To be defined by parent classes.\r\n        pass\r\n\r\n    def search_gadgets(self):\r\n\r\n        # To be defined by parent classes.\r\n        pass\r\n\r\n    # Attempt to build a gadget at the provided start address\r\n    # by verifying it properly terminates at the expected RETN.\r\n    def build_gadget(self, ea, ea_end):\r\n\r\n        # To be defined by parent classes.\r\n        return None\r\n\r\n    ###############################################################\r\n    # Decode instruction\r\n\r\n    def decode_instruction(self, insn, ea, ea_end):\r\n\r\n        # To be defined by parent classes.\r\n        pass\r\n\r\n###############################################################################\r\n# Sploiter Engine\r\n\r\nclass Sploiter():\r\n\r\n    def __init__(self):\r\n        \r\n\r\n\r\n        # Process modules list\r\n        self.modules = list()\r\n        self.rop     = None\r\n        self.funcptr = None\r\n\r\n        # Default patterns\r\n        self.c4_list = string.punctuation\r\n        self.c3_list = string.uppercase\r\n        self.c2_list = string.lowercase\r\n        self.c1_list = string.digits\r\n\r\n        # Check if processor supports 64-bit addressing\r\n        if idaapi.ph.flag & idaapi.PR_USE64:\r\n            self.addr64 = True\r\n            self.addr_format = \"%016X\"\r\n            self.pack_format_be = \">Q\"\r\n            self.pack_format_le = \"<Q\"\r\n        else:\r\n            self.addr64 = False\r\n            self.addr_format = \"%08X\"\r\n            self.pack_format_be = \">I\"\r\n            self.pack_format_le = \"<I\"\r\n\r\n    def get_func_ptr_instance(self):\r\n\r\n        # To be implemented by the plugin.\r\n        pass\r\n\r\n    def get_rop_instance(self):\r\n\r\n        # To be implemented by the plugin.\r\n        pass\r\n\r\n    def get_ptr_charset(self, ea):\r\n\r\n        ptr_charset = []\r\n\r\n        # Flags. True until proven otherwise.\r\n        nonull     = True\r\n        unicode    = True\r\n        ascii      = True\r\n        asciiprint = True        \r\n        alphanum   = True\r\n        alpha      = True\r\n        numeric    = True\r\n        \r\n        ptr_bytes = pack(self.pack_format_be, ea)\r\n        for i,b in enumerate( ptr_bytes ):\r\n\r\n            b_int = ord(b)\r\n\r\n            if b in self.ptrBadChars:\r\n                return None\r\n\r\n            # Locate any null bytes\r\n            if nonull and b == \"\\x00\":\r\n                nonull = False\r\n\r\n            # Unicode compatible address must have\r\n            # null bytes at even points in the address\r\n            if unicode and not i % 2:\r\n\r\n                if not ptr_bytes[i:i+2] in ASCII_TO_UNICODE[ self.unicodeTable ]:\r\n                    unicode = False\r\n\r\n            # Find any non-ascii characters\r\n            if ascii and not b_int > 127:\r\n\r\n                # Find any non-ascii printable characters\r\n                if asciiprint and not (b_int < 32 or b_int > 126):\r\n\r\n                    # Find any non-alphanumeric characters\r\n                    if alphanum and (b in string.ascii_letters or b in string.digits):\r\n\r\n                        # Find any non-numeric characters\r\n                        if numeric and not b in string.digits:\r\n                            numeric = False\r\n\r\n                        # Find any non-letter characters\r\n                        if alpha and not b in string.ascii_letters:\r\n                            alpha = False\r\n                    else:                        \r\n                        alphanum = False\r\n                        numeric  = False\r\n                        alpha     = False\r\n                else:                    \r\n                    asciiprint = False\r\n                    alphanum   = False\r\n                    numeric    = False\r\n                    alpha      = False\r\n            else:                \r\n                ascii      = False\r\n                asciiprint = False\r\n                alphanum   = False\r\n                numeric    = False\r\n                alpha      = False\r\n\r\n                # NOTE: You can continue to filter for upper/lower here if necessary\r\n        \r\n        if nonull:     ptr_charset.append(\"nonull\")\r\n\r\n        if unicode:    ptr_charset.append(\"unicode\")\r\n\r\n        if ascii:      \r\n            ptr_charset.append(\"ascii\")\r\n\r\n            if asciiprint: \r\n                ptr_charset.append(\"asciiprint\")\r\n\r\n                if alphanum:   \r\n                    ptr_charset.append(\"alphanum\")\r\n\r\n                    if numeric:    ptr_charset.append(\"numeric\")\r\n                    if alpha:      ptr_charset.append(\"alpha\")\r\n        \r\n\r\n        return ptr_charset  \r\n\r\n    def process_modules(self):\r\n\r\n        # Reset modules list\r\n        self.modules = list()\r\n\r\n        # Check if the debugger is current active, if not add one module entry for the main executable.\r\n        if idaapi.dbg_can_query() and idaapi.get_process_state() < 0:\r\n            for m in idautils.Modules():\r\n\r\n                module = Module(m.name, m.size, m.base, m.rebase_to)\r\n                self.modules.append(module)\r\n        else:\r\n            # Get the IDA info struct.\r\n            info = idaapi.get_inf_structure()\r\n\r\n            # NOTE: There is no universal way in IDA SDK to get the base address/size of a loaded file because\r\n            # some of the loaders do not fill out the module information structure when loading the input file.\r\n            # To get around this I hacked in information that is both dynamically pulled from the database and\r\n            # \"good enough\", by using the maxEA and minEA of the loaded file. Since we are only searching the\r\n            # segments of the input file and they will all fall within this range this should be sufficient even\r\n            # though the size and base address fields are not accurate.\r\n            #\r\n            # I will buy beer for anyone who can come up with a universal way to get the base address and size\r\n            # of the loaded input file regardless of format or loader module used to load it. You also can't reparse\r\n            # the original file.\r\n\r\n            # Fake the module information.\r\n            module = Module(idaapi.get_root_filename(), info.maxEA - info.minEA, info.minEA, 0)      # name, size, base, rebase_to\r\n            self.modules.append(module)\r\n\r\n    def show_modules_view(self):\r\n        mod = ModuleView(self)\r\n        mod.show()\r\n\r\n    def process_rop(self, select_list = None):\r\n\r\n        # Initialize ROP gadget search engine\r\n        self.rop = self.get_rop_instance()\r\n        if self.rop is None:\r\n            return\r\n\r\n        # Prompt user for ROP search settings\r\n        f = RopForm(self, select_list)\r\n        ok = f.Execute()\r\n        if ok == 1:\r\n\r\n            # Configure ROP gadget search engine\r\n\r\n            # Get selected modules\r\n            self.rop.modules = [self.modules[i] for i in f.mod.GetEmbSelection()]\r\n\r\n            if len(self.rop.modules) > 0:\r\n\r\n                # Pointer filters\r\n                self.rop.ptrNonull     = f.cPtrNonull.checked\r\n                self.rop.ptrUnicode    = f.cPtrUnicode.checked\r\n                self.rop.ptrAscii      = f.cPtrAscii.checked\r\n                self.rop.ptrAsciiPrint = f.cPtrAsciiPrint.checked\r\n                self.rop.ptrAlphaNum   = f.cPtrAlphaNum.checked\r\n                self.rop.ptrAlpha      = f.cPtrAlpha.checked\r\n                self.rop.ptrNum        = f.cPtrNum.checked\r\n\r\n                # Filter bad characters\r\n                buf                    = f.strBadChars.value\r\n                buf = buf.replace(' ','')         # remove spaces\r\n                buf = buf.replace('\\\\x','')       # remove '\\x' prefixes\r\n                buf = buf.replace('0x','')        # remove '0x' prefixes\r\n                try:\r\n                    buf = binascii.unhexlify(buf) # convert to bytes\r\n                    self.ptrBadChars   = buf\r\n                except Exception, e:\r\n                    idaapi.warning(\"Invalid input: %s\" % e)\r\n                    self.ptrBadChars   = \"\"\r\n\r\n                # Ascii_to_Unicode_transformation table\r\n                # BUG: DropdownControl does not work on IDA 6.5\r\n                self.unicodeTable      = f.radUnicode.value\r\n\r\n                # ROP instruction filters\r\n                self.rop.ropBadMnems   = [mnem.strip().lower() for mnem in f.strBadMnems.value.split(',')]\r\n                self.rop.ropAllowJcc   = f.cRopAllowJcc.checked\r\n                self.rop.ropNoBadBytes = f.cRopNoBadBytes.checked\r\n\r\n                # Get ROP engine settings\r\n                self.rop.maxRopSize    = f.intMaxRopSize.value\r\n                self.rop.maxRopOffset  = f.intMaxRopOffset.value\r\n                self.rop.maxRops       = f.intMaxRops.value\r\n                self.rop.maxRetnImm    = f.intMaxRetnImm.value\r\n\r\n                # Gadget search values\r\n                self.rop.searchRop     = f.cRopSearch.checked\r\n                self.rop.searchJop     = f.cJopSearch.checked\r\n\r\n                # Search for returns and ROP gadgets\r\n                self.rop.search_retns()\r\n                self.rop.search_gadgets()\r\n\r\n                # Show the ROP gadgets view\r\n                ropView = RopView(self)\r\n                ropView.show()\r\n\r\n            else:\r\n                idaapi.warning(\"No modules selected.\")\r\n\r\n        f.Free()\r\n\r\n    def process_funcptr(self, select_list = None):\r\n\r\n        # Prompt user for function pointer search settings\r\n        f = PtrForm(self, select_list)\r\n        ok = f.Execute()\r\n        if ok == 1:\r\n\r\n            # Initialize Function Pointer search engine\r\n            self.funcptr = self.get_func_ptr_instance()\r\n            if self.funcptr is None:\r\n                return\r\n\r\n            # Configure Function Pointer search engine\r\n\r\n            # Get selected modules\r\n            self.funcptr.modules = [self.modules[i] for i in f.mod.GetEmbSelection()]\r\n\r\n            if len(self.funcptr.modules) > 0:\r\n\r\n                # Pointer filters\r\n                self.funcptr.ptrNonull     = f.cPtrNonull.checked\r\n                self.funcptr.ptrUnicode    = f.cPtrUnicode.checked\r\n                self.funcptr.ptrAscii      = f.cPtrAscii.checked\r\n                self.funcptr.ptrAsciiPrint = f.cPtrAsciiPrint.checked\r\n                self.funcptr.ptrAlphaNum   = f.cPtrAlphaNum.checked\r\n                self.funcptr.ptrAlpha      = f.cPtrAlpha.checked\r\n                self.funcptr.ptrNum        = f.cPtrNum.checked\r\n\r\n                # Apply pointer filters to the funcptr or ptr-to-ptr\r\n                if f.rFilterP2P.selected:\r\n                    self.funcptr.filterP2P = True\r\n                else:\r\n                    self.funcptr.filterP2P = False\r\n\r\n                # Ascii_to_Unicode_transformation table\r\n                # BUG: DropdownControl does not work on IDA 6.5\r\n                self.unicodeTable      = f.radUnicode.value\r\n\r\n                # Filter bad characters\r\n                buf                    = f.strBadChars.value\r\n                buf = buf.replace(' ','')         # remove spaces\r\n                buf = buf.replace('\\\\x','')       # remove '\\x' prefixes\r\n                buf = buf.replace('0x','')        # remove '0x' prefixes\r\n                try:\r\n                    buf = binascii.unhexlify(buf) # convert to bytes\r\n                    self.ptrBadChars = buf\r\n                except Exception, e:\r\n                    idaapi.warning(\"Invalid input: %s\" % e)\r\n                    self.ptrBadChars = \"\"\r\n\r\n                # Offsets\r\n                self.funcptr.ptrOffset = int(f.intPtrOffset.value, 16)\r\n                self.funcptr.p2pOffset = int(f.intP2POffset.value, 16)\r\n\r\n                # Pointer search engine settings\r\n                self.funcptr.searchP2P = not f.rSearchPtrOnly.checked\r\n                self.funcptr.maxPtrs   = f.intMaxPtrs.value\r\n\r\n                # Search for writable pointers\r\n                self.funcptr.search_pointers()\r\n\r\n                # Show the writable pointers view\r\n                ptrView = PtrView(self)\r\n                ptrView.show()\r\n\r\n            else:\r\n                idaapi.warning(\"No modules selected.\")\r\n\r\n        f.Free()\r\n\r\n    def pattern_create(self):\r\n\r\n        f = PatternCreateForm(self)\r\n        ok = f.Execute()\r\n        if ok == 1:  \r\n            pass\r\n\r\n        f.Free()\r\n\r\n    def pattern_detect(self, debugger=True):\r\n\r\n        f = PatternDetectForm(self, debugger)\r\n        ok = f.Execute()\r\n        if ok == 1:  \r\n            pass\r\n\r\n        f.Free()\r\n\r\n    def process_compare(self, debugger=True):\r\n\r\n        f = CompareForm(self, debugger)\r\n        ok = f.Execute()\r\n        if ok == 1:\r\n            pass\r\n\r\n        f.Free()\r\n\r\n\r\n###############################################################################\r\n# Sploiter UI\r\n###############################################################################\r\n\r\n###############################################################################\r\n# Module UI\r\n###############################################################################\r\n\r\nclass ModuleView(Choose2):\r\n    \"\"\"\r\n    Chooser class to display security characteristics of loaded modules.\r\n    \"\"\"\r\n    def __init__(self, sploiter, embedded = False):\r\n\r\n        self.sploiter = sploiter\r\n\r\n        Choose2.__init__(self,\r\n                         \"Modules\",\r\n                         [ [\"Address\",  13 | Choose2.CHCOL_HEX], \r\n                           [\"Name\",     10 | Choose2.CHCOL_PLAIN], \r\n                           [\"Size\",     10 | Choose2.CHCOL_HEX],\r\n                           [\"SafeSEH\",   6 | Choose2.CHCOL_PLAIN],\r\n                           [\"ASLR\",      6 | Choose2.CHCOL_PLAIN], \r\n                           [\"DEP\",       6 | Choose2.CHCOL_PLAIN],\r\n                           [\"Canary\",    6 | Choose2.CHCOL_PLAIN],\r\n                           [\"Path\",     40 | Choose2.CHCOL_PLAIN], \r\n                         ],\r\n                         flags = Choose2.CH_MULTI,  # Select multiple modules\r\n                         embedded=embedded)\r\n\r\n        self.icon = 150\r\n\r\n        # Items for display\r\n        self.items = list()\r\n\r\n        # Initialize/Refresh the view\r\n        self.refreshitems()\r\n\r\n        # Selected items\r\n        self.select_list = list()\r\n\r\n        # Command callbacks\r\n        self.cmd_load_module     = None\r\n        self.cmd_search_gadgets  = None\r\n        self.cmd_search_pointers = None\r\n\r\n    def show(self):\r\n        # Attempt to open the view\r\n        if self.Show() < 0: return False\r\n\r\n        # Add extra context menu commands\r\n        # NOTE: Make sure you check for duplicates\r\n        if self.cmd_load_module == None:\r\n            self.cmd_load_module = self.AddCommand(\"Load module...\", flags = idaapi.CHOOSER_POPUP_MENU, icon=135)\r\n        if self.cmd_search_gadgets == None:\r\n            self.cmd_search_gadgets = self.AddCommand(\"Search gadgets...\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=182 )\r\n        if self.cmd_search_pointers == None and self.sploiter.is_func_ptr_supported() == True:\r\n            self.cmd_search_pointers = self.AddCommand(\"Search function pointers...\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=143 )\r\n\r\n\r\n        return True\r\n\r\n    def refreshitems(self):\r\n        self.items = list()\r\n\r\n        for m in self.sploiter.modules:\r\n            self.items.append([ self.sploiter.addr_format % m.addr, \r\n                                m.file, \r\n                                \"%08X\" % m.size,\r\n                                m.SafeSEH, m.ASLR,\r\n                                m.NXCompat,\r\n                                m.GS,\r\n                                m.path])\r\n\r\n    def OnCommand(self, n, cmd_id):\r\n\r\n        # Search ROP gadgets\r\n        if cmd_id == self.cmd_search_gadgets:\r\n\r\n            # Empty selection\r\n            if n == -1:\r\n\r\n                # Initialize ROP gadget form with empty selection\r\n                self.sploiter.process_rop(select_list = self.select_list)\r\n\r\n            # Selection start\r\n            elif n == -2:\r\n                self.select_list = list()\r\n\r\n            # Selection end\r\n            elif n == -3:\r\n\r\n                # Initialize ROP gadget form with user selection\r\n                self.sploiter.process_rop(select_list = self.select_list)\r\n                self.select_list = list()\r\n\r\n            # Selection number\r\n            else:\r\n                self.select_list.append(n)\r\n\r\n        # Search function pointers\r\n        elif cmd_id == self.cmd_search_pointers:\r\n\r\n            # Empty selection\r\n            if n == -1:\r\n\r\n                # Initialize function pointers form with empty selection\r\n                self.sploiter.process_funcptr(select_list = self.select_list)\r\n\r\n            # Selection start\r\n            elif n == -2:\r\n                self.select_list = list()\r\n\r\n            # Selection end\r\n            elif n == -3:\r\n\r\n                # Initialize function pointers form with user selection\r\n                self.sploiter.process_funcptr(select_list = self.select_list)\r\n                self.select_list = list()\r\n\r\n            # Selection number\r\n            else:\r\n                self.select_list.append(n)\r\n\r\n        elif cmd_id == self.cmd_load_module:\r\n\r\n            module_name = idaapi.askfile_c(0, \"*.*\", \"Please select module to load\")\r\n            if module_name:\r\n                print \"[idasploiter] Loading module: %s\" % module_name     \r\n                loadlib = idaapi.Appcall.proto(\"kernel32_LoadLibraryA\", \"int __stdcall loadlib(const char *fn);\")\r\n                hmod = loadlib(module_name)\r\n                if hmod:\r\n                    print \"[idasploiter] Finished loading module: %s\" % module_name\r\n                else:\r\n                    print \"[idasploiter] Could not load: %s\" % module_name\r\n\r\n                self.refreshitems()\r\n\r\n        return 1\r\n\r\n    def OnSelectLine(self, n):\r\n        pass\r\n\r\n    def OnGetLine(self, n):\r\n        return self.items[n]\r\n\r\n    def OnGetIcon(self, n):\r\n\r\n        if not len(self.items) > 0:\r\n            return -1\r\n\r\n        m = self.sploiter.modules[n]\r\n        if m.SafeSEH != \"No\" and m.ASLR == \"Yes\" and m.NXCompat == \"Yes\" and m.GS != \"No\":\r\n            return 61\r\n        elif m.ASLR == \"Yes\":\r\n            return 60\r\n        else:\r\n            return 59\r\n\r\n    def OnClose(self):\r\n        self.cmd_search_gadgets = None\r\n        self.cmd_search_pointers    = None\r\n\r\n    def OnGetSize(self):\r\n        return len(self.items)\r\n\r\n    def OnRefresh(self, n):\r\n        self.refreshitems()\r\n        return n\r\n\r\n    def OnActivate(self):\r\n        self.refreshitems()\r\n\r\n###############################################################################\r\n# ROP UI\r\n###############################################################################\r\n\r\n###############################################################################\r\n# ROP/JOP/COP Form\r\n\r\nclass RopForm(Form):\r\n\r\n    def __init__(self, sploiter, select_list = None):\r\n\r\n        self.sploiter = sploiter\r\n        self.select_list = select_list\r\n\r\n        self.mod = ModuleView(self.sploiter, embedded=True)\r\n\r\n        Form.__init__(self, \r\nr\"\"\"BUTTON YES* Search\r\nSearch ROP gadgets\r\n\r\n{FormChangeCb}<Modules:{cEChooser}>\r\n\r\nPointer Charset:                  Search Settings:\r\n<nonull:{cPtrNonull}>        <Bad Chars        :{strBadChars}>     \r\n<unicode:{cPtrUnicode}>       Unicode Table    <ANSI:{rUnicodeANSI}><OEM:{rUnicodeOEM}><UTF7:{rUnicodeUTF7}><UTF8:{rUnicodeUTF8}>{radUnicode}>\r\n<ascii:{cPtrAscii}>         <Bad Instructions :{strBadMnems}>\r\n<asciiprint:{cPtrAsciiPrint}>    <Max gadget size  :{intMaxRopSize}>\r\n<alphanum:{cPtrAlphaNum}>      <Max gadget offset:{intMaxRopOffset}>\r\n<alpha:{cPtrAlpha}>         <Max RETN imm16   :{intMaxRetnImm}>\r\n<numeric:{cPtrNum}>{ptrGroup}>       <Max JOP imm8/32  :{intMaxJopImm}>\r\n                <Max gadgets      :{intMaxRops}>\r\n                Other settings   <Allow conditional jumps:{cRopAllowJcc}>\r\n                <Do not allow bad bytes:{cRopNoBadBytes}>\r\n                <Search for ROP gadgets:{cRopSearch}>\r\n                <Search for JOP gadgets:{cJopSearch}>{ropGroup}>\r\n\r\n\r\n\"\"\", {\r\n                'cEChooser'       : Form.EmbeddedChooserControl(self.mod, swidth=131),\r\n                'ptrGroup'        : Form.ChkGroupControl((\"cPtrNonull\", \"cPtrAscii\", \"cPtrAsciiPrint\", \"cPtrUnicode\",'cPtrAlphaNum','cPtrAlpha','cPtrNum')),\r\n                'ropGroup'        : Form.ChkGroupControl(('cRopAllowJcc','cRopNoBadBytes','cRopSearch','cJopSearch')),\r\n                'intMaxRopSize'   : Form.NumericInput(swidth=4,tp=Form.FT_DEC,value=self.sploiter.rop.maxRopSize),\r\n                'intMaxRopOffset' : Form.NumericInput(swidth=4,tp=Form.FT_DEC,value=self.sploiter.rop.maxRopOffset),\r\n                'intMaxRops'      : Form.NumericInput(swidth=4,tp=Form.FT_DEC,value=self.sploiter.rop.maxRops),\r\n                'intMaxRetnImm'   : Form.NumericInput(swidth=4,tp=Form.FT_HEX,value=self.sploiter.rop.maxRetnImm),\r\n                'intMaxJopImm'    : Form.NumericInput(swidth=4,tp=Form.FT_HEX,value=self.sploiter.rop.maxJopImm),\r\n                'strBadChars'     : Form.StringInput(swidth=70,tp=Form.FT_ASCII),\r\n                'radUnicode'      : Form.RadGroupControl((\"rUnicodeANSI\",\"rUnicodeOEM\",\"rUnicodeUTF7\",\"rUnicodeUTF8\")),\r\n                'strBadMnems'     : Form.StringInput(swidth=80,tp=Form.FT_ASCII,value=self.sploiter.bad_instructions),\r\n                'FormChangeCb'    : Form.FormChangeCb(self.OnFormChange),\r\n            })\r\n\r\n        self.Compile()\r\n\r\n    def OnFormChange(self, fid):\r\n\r\n        # Form initialization\r\n        if fid == -1:\r\n            self.SetFocusedField(self.cEChooser)\r\n\r\n            # Preselect non-ASLR modules on startup if none were already specified\r\n            if self.select_list == None:\r\n\r\n                self.select_list = list()\r\n                for i, m in enumerate(self.sploiter.modules):\r\n                    if m.ASLR == \"No\":\r\n                        self.select_list.append(i)\r\n\r\n            self.SetControlValue(self.cEChooser, self.select_list)\r\n\r\n            # Enable both ROP and JOP search by default\r\n            self.SetControlValue(self.cRopSearch, True)\r\n            self.SetControlValue(self.cJopSearch, True)\r\n\r\n            # Skip bad instructions by default\r\n            self.SetControlValue(self.cRopNoBadBytes, True)\r\n\r\n        # Form OK pressed\r\n        elif fid == -2:\r\n            pass\r\n\r\n        return 1\r\n\r\n###############################################################################\r\n# ROP Viewer\r\n\r\nclass RopView(Choose2):\r\n    \"\"\"\r\n    Chooser class to display security characteristics of loaded modules.\r\n    \"\"\"\r\n    def __init__(self, sploiter):\r\n\r\n        self.sploiter = sploiter\r\n\r\n        Choose2.__init__(self,\r\n                         \"ROP gadgets\",\r\n                         [ [\"Address\",           13 | Choose2.CHCOL_HEX], \r\n                           [\"Gadget\",            30 | Choose2.CHCOL_PLAIN], \r\n                           [\"Module\",            10 | Choose2.CHCOL_PLAIN],\r\n                           [\"Size\",               3 | Choose2.CHCOL_DEC],\r\n                           [\"Pivot\",              4 | Choose2.CHCOL_DEC],\r\n                           [\"Operations\",         12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Changed Registers\", 12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Used Registers\",    12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Charset\",           12 | Choose2.CHCOL_PLAIN],\r\n                         ],\r\n                         flags = Choose2.CH_MULTI)\r\n\r\n        self.icon = 182\r\n\r\n        # Items for display\r\n        self.items = []\r\n\r\n        # Initialize/Refresh the view\r\n        self.refreshitems()\r\n\r\n        # Selected items\r\n        self.gadget_chain = list()\r\n\r\n        # Command callbacks\r\n        self.cmd_chain_add   = None\r\n        self.cmd_chain_build = None\r\n        self.cmd_chain_clear = None\r\n        self.cmd_export_csv  = None\r\n\r\n\r\n    def show(self):\r\n        # Attempt to open the view\r\n        if self.Show() < 0: return False\r\n\r\n        if self.cmd_chain_add == None:\r\n            self.cmd_chain_add   = self.AddCommand(\"Add to chain\",     flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=50)\r\n        if self.cmd_chain_build == None:\r\n            self.cmd_chain_build = self.AddCommand(\"Build chain\",      flags = idaapi.CHOOSER_POPUP_MENU, icon=156)\r\n        if self.cmd_chain_clear == None:\r\n            self.cmd_chain_clear = self.AddCommand(\"Clear chain\",      flags = idaapi.CHOOSER_POPUP_MENU, icon=32)\r\n        if self.cmd_export_csv == None:\r\n            self.cmd_export_csv  = self.AddCommand(\"Export as csv...\", flags = idaapi.CHOOSER_POPUP_MENU, icon=40)\r\n\r\n        return True\r\n\r\n    def refreshitems(self):\r\n        self.items = []\r\n\r\n        for g in self.sploiter.rop.gadgets:\r\n\r\n            self.items.append([ self.sploiter.addr_format % g.address, \r\n                                \" # \".join(g.instructions), \r\n                                g.module, \r\n                                \"%d\" % g.size, \r\n                                \"%d\" % g.pivot, \r\n                                \", \".join(g.operations), \r\n                                \", \".join(g.chg_registers), \r\n                                \", \".join(g.use_registers), \r\n                                \", \".join(g.ptr_charset)\r\n                                ])\r\n\r\n    def OnCommand(self, n, cmd_id):\r\n\r\n        # Build ROP chain\r\n        if cmd_id == self.cmd_chain_build:\r\n\r\n            # Display ROP chain builder form\r\n            f = RopChainForm(self)\r\n            ok = f.Execute()\r\n            if ok == 1:\r\n                pass\r\n            f.Free()\r\n\r\n        # Clear ROP chain\r\n        elif cmd_id == self.cmd_chain_clear:\r\n            self.gadget_chain = list()\r\n\r\n        # Add gadget to ROP chain\r\n        elif cmd_id == self.cmd_chain_add:\r\n            if n >= 0:\r\n                self.gadget_chain.append( self.sploiter.rop.gadgets[n] )\r\n\r\n        # Export CSV\r\n        elif cmd_id == self.cmd_export_csv:\r\n\r\n            file_name = idaapi.askfile_c(1, \"*.csv\", \"Please enter CSV file name\")\r\n            if file_name:\r\n                print \"[idasploiter] Exporting gadgets to %s\" % file_name\r\n                with open(file_name, 'wb') as csvfile:\r\n                    csvwriter = csv.writer(csvfile, delimiter=',',\r\n                                            quotechar='\"', quoting=csv.QUOTE_MINIMAL)\r\n                    csvwriter.writerow([\"Address\",\"Gadget\",\"Module\",\"Size\",\"Pivot\",\"Operations\",\"Changed Registers\",\"Used Registers\",\"Charset\"])\r\n                    for item in self.items:\r\n                        csvwriter.writerow(item)\r\n\r\n        return 1\r\n\r\n    def OnSelectLine(self, n):\r\n        idaapi.jumpto( self.sploiter.rop.gadgets[n].address )\r\n\r\n    def OnGetLine(self, n):\r\n        return self.items[n]\r\n\r\n    def OnClose(self):\r\n        self.cmd_chain_add   = None\r\n        self.cmd_chain_build = None\r\n        self.cmd_chain_clear = None\r\n        self.cmd_export_csv  = None\r\n\r\n    def OnGetSize(self):\r\n        return len(self.items)\r\n\r\n    def OnRefresh(self, n):\r\n        self.refreshitems()\r\n        return n\r\n\r\n    def OnActivate(self):\r\n        self.refreshitems()\r\n\r\n###############################################################################\r\n# ROP Chain Builder UI\r\n###############################################################################\r\n\r\n###############################################################################\r\n# ROP Chain Viewer\r\n\r\nclass RopChainView(Choose2):\r\n    \"\"\"\r\n    Chooser class to display security characteristics of loaded modules.\r\n    \"\"\"\r\n    def __init__(self, ropview):\r\n\r\n        self.ropview = ropview\r\n\r\n        Choose2.__init__(self,\r\n                         \"ROP gadgets\",\r\n                         [ [\"Address\",           13 | Choose2.CHCOL_HEX], \r\n                           [\"Gadget\",            30 | Choose2.CHCOL_PLAIN], \r\n                           [\"Module\",            10 | Choose2.CHCOL_PLAIN],\r\n                           [\"Size\",               3 | Choose2.CHCOL_DEC],\r\n                           [\"Pivot\",              4 | Choose2.CHCOL_DEC],\r\n                           [\"Operations\",        12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Changed Registers\", 12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Used Registers\",    12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Charset\",           12 | Choose2.CHCOL_PLAIN],\r\n                         ],\r\n                         flags = Choose2.CH_MULTI,\r\n                         embedded = True)\r\n\r\n        self.icon = 182\r\n\r\n        # Items for display and corresponding data\r\n        self.items = []\r\n\r\n        # Selected items\r\n        self.select_list = list()\r\n\r\n        # Initialize/Refresh the view\r\n        self.refreshitems()\r\n\r\n    def refreshitems(self):\r\n        self.items = []\r\n\r\n        for g in self.ropview.gadget_chain:\r\n\r\n            self.items.append([ self.ropview.sploiter.addr_format % g.address, \r\n                                \" # \".join(g.instructions), \r\n                                g.module, \r\n                                \"%d\" % g.size if g.size else \"\", \r\n                                \"%d\" % g.pivot if g.pivot else \"\", \r\n                                \", \".join(g.operations), \r\n                                \", \".join(g.chg_registers), \r\n                                \", \".join(g.use_registers), \r\n                                \", \".join(g.ptr_charset)\r\n                                ])\r\n\r\n        return\r\n\r\n    def OnCommand(self, n, cmd_id):\r\n\r\n        if cmd_id == self.cmd_move_up:\r\n            if n > 0:\r\n                self.ropview.gadget_chain.insert(n-1, self.ropview.gadget_chain.pop(n))\r\n\r\n        # NOTE: Moving items down should be done in one go in reverse\r\n        #       to avoid self.items from desyncing from gadget_chain list.\r\n        elif cmd_id == self.cmd_move_down:\r\n\r\n            # Empty selection\r\n            if n == -1:\r\n                pass\r\n\r\n            # Selection start\r\n            elif n == -2:\r\n                self.select_list = list()\r\n\r\n            # Selection end\r\n            elif n == -3:\r\n                for i in sorted(self.select_list, reverse=True):\r\n                    self.ropview.gadget_chain.insert(i+1, self.ropview.gadget_chain.pop(i))\r\n                self.select_list = list()\r\n\r\n            else:\r\n                self.select_list.append(n)\r\n\r\n        # NOTE: Duplicating items should be done in one go in reverse\r\n        #       to avoid self.items desyncing from gadget_chain list.\r\n        elif cmd_id == self.cmd_duplicate:\r\n            \r\n            # Empty selection\r\n            if n == -1:\r\n                pass\r\n\r\n            # Selection start\r\n            elif n == -2:\r\n                self.select_list = list()\r\n\r\n            # Selection end\r\n            elif n == -3:\r\n\r\n                # Duplicate selection after the last index\r\n                last_i = self.select_list[-1]\r\n\r\n                # Duplicate selected items in reverse\r\n                for i in sorted(self.select_list, reverse=True):\r\n\r\n                    if last_i == len(self.ropview.gadget_chain) - 1:\r\n                        self.ropview.gadget_chain.append(self.ropview.gadget_chain[i])\r\n                    else:\r\n                        self.ropview.gadget_chain.insert(last_i + 1, self.ropview.gadget_chain[i])\r\n\r\n                self.select_list = list()\r\n\r\n            else:\r\n                self.select_list.append(n)\r\n\r\n        # NOTE: Deleting items should be done in one go in reverse\r\n        #       to avoid self.items desyncing from gadget_chain list.\r\n        elif cmd_id == self.cmd_delete:\r\n            \r\n            # Empty selection\r\n            if n == -1:\r\n                pass\r\n\r\n            # Selection start\r\n            elif n == -2:\r\n                self.select_list = list()\r\n\r\n            # Selection end\r\n            elif n == -3:\r\n                for i in sorted(self.select_list, reverse=True):\r\n                    del self.ropview.gadget_chain[i]\r\n                self.select_list = list()\r\n\r\n            else:\r\n                self.select_list.append(n)\r\n\r\n\r\n\r\n        return 1\r\n\r\n    def OnSelectLine(self, n):\r\n        pass\r\n\r\n    def OnGetLine(self, n):\r\n        return self.items[n]\r\n\r\n    def OnClose(self):\r\n        pass\r\n\r\n    def OnGetSize(self):\r\n        return len(self.items)\r\n\r\n    def OnRefresh(self, n):\r\n        self.refreshitems()\r\n        return n\r\n\r\n    def OnRefreshed(self):\r\n        self.refreshitems()\r\n        return len(self.items)\r\n\r\n    def OnActivate(self):\r\n        self.refreshitems()\r\n\r\n\r\n###############################################################################\r\n# ROPChain Form\r\n\r\nclass RopChainForm(Form):\r\n\r\n    def __init__(self, ropview):\r\n\r\n        self.ropview = ropview\r\n\r\n        self.ropchainview = RopChainView(self.ropview)\r\n\r\n        Form.__init__(self, \r\nr\"\"\"BUTTON YES* NONE\r\nBUTTON CANCEL NONE\r\nROP Chain Builder\r\n\r\n{FormChangeCb}<ROP gadgets:{cEChooser}>\r\n<:{strAddr}><:{strComment}><Insert:{iButtonInsert}>\r\n<:{strRopChain}>\r\nFormats<Plain:{rFmtPlain}><Python:{rFmtPython}><Ruby:{rFmtRuby}><Perl:{rFmtPerl}><JavaScript:{rFmtJS}>{rGroup}> \r\n{spacer}<Generate:{iButtonGenerate}>\r\n\"\"\", {\r\n                'spacer'          : Form.StringLabel(\"                                \"),\r\n                'cEChooser'       : Form.EmbeddedChooserControl(self.ropchainview, swidth=125),\r\n                'strAddr'         : Form.StringInput(value=\"0x4141414141414141\" if self.ropview.sploiter.addr64 else \"0x41414141\", swidth=10),\r\n                'strComment'      : Form.StringInput(value=\"padding\", swidth=20),\r\n                'iButtonInsert'   : Form.ButtonInput(self.OnButtonInsert, swidth=5),\r\n                'strRopChain'     : Form.MultiLineTextControl(text=\"\", swidth=125, flags = Form.MultiLineTextControl.TXTF_FIXEDFONT),\r\n                'rGroup'          : Form.RadGroupControl((\"rFmtPlain\",\"rFmtPython\", \"rFmtRuby\", \"rFmtPerl\", \"rFmtJS\") ),\r\n                'iButtonGenerate' : Form.ButtonInput(self.OnButtonGenerate, swidth=5),\r\n                'FormChangeCb'    : Form.FormChangeCb(self.OnFormChange),\r\n            })\r\n\r\n        self.Compile()\r\n\r\n    def OnFormChange(self, fid):\r\n\r\n        # Form initialization\r\n        if fid == -1:\r\n            self.SetFocusedField(self.cEChooser)\r\n\r\n            # Add commands to embedded view\r\n            self.ropchainview.cmd_move_up   = self.cEChooser.AddCommand(\"Move Up\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION | idaapi.CHOOSER_HOTKEY, icon=86)\r\n            self.ropchainview.cmd_move_down = self.cEChooser.AddCommand(\"Move Down\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=85)\r\n            self.ropchainview.cmd_duplicate = self.cEChooser.AddCommand(\"Duplicate\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=111)\r\n            self.ropchainview.cmd_delete    = self.cEChooser.AddCommand(\"Delete\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=112)\r\n\r\n        # Form OK pressed\r\n        elif fid == -2:\r\n            pass\r\n\r\n        return 1\r\n\r\n    def OnButtonInsert(self, code=0):\r\n        # Get user input\r\n        address = self.GetControlValue(self.strAddr)\r\n        address = int(address,16)\r\n\r\n        comment = self.GetControlValue(self.strComment)\r\n\r\n        # Create a dummy gadget\r\n        gadget = Gadget(instructions = [comment,], pivot = 0, operations = [], chg_registers = [], use_registers = [])\r\n        gadget.address = address\r\n        gadget.size = None\r\n        gadget.pivot = None\r\n\r\n        # Insert dummy gadget at selected positions\r\n        select_list = self.GetControlValue(self.cEChooser)\r\n        if select_list:\r\n            for i in sorted(select_list,reverse=True):\r\n                self.ropview.gadget_chain.insert(i + 1, gadget)\r\n        else:\r\n            self.ropview.gadget_chain.append(gadget)\r\n\r\n        # Update the view\r\n        self.RefreshField(self.cEChooser)\r\n\r\n    # TODO: Generate relative addresses to a dynamically determined module base\r\n    #       (e.g. ROP chain built based on a leaked or calculated base address)\r\n    def OnButtonGenerate(self, code=0):\r\n\r\n        ropchain = \"\"\r\n\r\n        if self.ropview.sploiter.addr64:\r\n            addr_format = \"%016X\"\r\n            pack_format_python = \"<Q\"\r\n            pack_format_ruby = \"Q<\"\r\n            pack_format_perl = \"Q<\"\r\n            pack_words_js = 4\r\n            pack_bytes_c = 8\r\n\r\n        else:\r\n            addr_format = \"%08X\"\r\n            pack_format_python = \"<I\"\r\n            pack_format_ruby = \"V\"\r\n            pack_format_perl = \"V\"\r\n            pack_words_js = 2\r\n            pack_bytes_c = 4\r\n\r\n        # Plain output\r\n        if self.GetControlValue(self.rGroup) == 0:\r\n\r\n            ropchain += \"// Generated by IDA Sploiter\\n\"\r\n\r\n            for g in self.ropview.gadget_chain:\r\n\r\n                bytes =  [\"\\\\x%02x\" % b for b in struct.unpack(\"B\"*pack_bytes_c, struct.pack(pack_format_python, g.address))]\r\n\r\n                ropchain += \"\\\"%s\\\" // %s # %s\\n\" % (\r\n                                ''.join(bytes),\r\n                                addr_format % g.address,\r\n                                \" # \".join(g.instructions))\r\n\r\n        # Python\r\n        elif self.GetControlValue(self.rGroup) == 1:\r\n\r\n            ropchain += \"# Generated by IDA Sploiter\\n\"\r\n\r\n            for i, g in enumerate(self.ropview.gadget_chain):\r\n\r\n                ropchain += \"rop_chain %s= struct.pack('%s', 0x%s) # %s\\n\" % (\r\n                                '+' if i > 0 else ' ',\r\n                                pack_format_python,\r\n                                addr_format % g.address,\r\n                                \" # \".join(g.instructions) )\r\n\r\n        # Ruby\r\n        elif self.GetControlValue(self.rGroup) == 2:\r\n\r\n            ropchain += \"# Generated by IDA Sploiter\\n\"\r\n\r\n            for i, g in enumerate(self.ropview.gadget_chain):\r\n\r\n                ropchain += \"rop_chain %s [0x%s].pack('%s') # %s\\n\" % (\r\n                                '<<' if i > 0 else ' =',\r\n                                addr_format % g.address,\r\n                                pack_format_ruby,\r\n                                \" # \".join(g.instructions) )\r\n\r\n        # Perl\r\n        elif self.GetControlValue(self.rGroup) == 3:\r\n\r\n            ropchain += \"# Generated by IDA Sploiter\\n\"\r\n\r\n            for i, g in enumerate(self.ropview.gadget_chain):\r\n\r\n                ropchain += \"%s$rop_chain %s= pack('%s', 0x%s); # %s\\n\" % (\r\n                                'my ' if i == 0 else '',\r\n                                '.' if i > 0 else ' ',\r\n                                pack_format_perl,\r\n                                addr_format % g.address,\r\n                                \" # \".join(g.instructions) )\r\n\r\n        # JavaScript\r\n        elif self.GetControlValue(self.rGroup) == 4:\r\n\r\n            ropchain += \"// Generated by IDA Sploiter\\n\"\r\n\r\n            for i, g in enumerate(self.ropview.gadget_chain):\r\n\r\n                words_js = [\"%%u%04x\" % w for w in struct.unpack(\"H\"*pack_words_js, struct.pack(pack_format_python, g.address))]\r\n\r\n                ropchain += \"rop_chain %s= unescape(\\\"%s\\\"); // %s # %s\\n\" % (\r\n                                '+' if i > 0 else ' ',\r\n                                ''.join(words_js),\r\n                                addr_format % g.address,\r\n                                \" # \".join(g.instructions) )\r\n\r\n        strRopChain = idaapi.textctrl_info_t(text=ropchain, flags = Form.MultiLineTextControl.TXTF_FIXEDFONT)\r\n        self.SetControlValue(self.strRopChain, strRopChain)\r\n\r\n###############################################################################\r\n# Function Pointer UI\r\n###############################################################################\r\n\r\n###############################################################################\r\n# Function Pointer Form\r\n\r\nclass PtrForm(Form):\r\n\r\n    def __init__(self, sploiter, select_list = None):\r\n\r\n        self.sploiter = sploiter\r\n        self.select_list = select_list\r\n        self.mod = ModuleView(self.sploiter, embedded=True)\r\n\r\n        Form.__init__(self, \r\nr\"\"\"BUTTON YES* Search\r\nSearch writable function pointers\r\n\r\n{FormChangeCb}<Modules:{cEChooser}>\r\n\r\nPointer Charset:                  Search Settings:\r\n<nonull:{cPtrNonull}>        <Bad chars     :{strBadChars}>\r\n<unicode:{cPtrUnicode}>       Unicode Table <ANSI:{rUnicodeANSI}><OEM:{rUnicodeOEM}><UTF7:{rUnicodeUTF7}><UTF8:{rUnicodeUTF8}>{radUnicode}>\r\n<ascii:{cPtrAscii}>         <PTR Offset    :{intPtrOffset}> \r\n<asciiprint:{cPtrAsciiPrint}>    <P2P Offset    :{intP2POffset}>\r\n<alphanum:{cPtrAlphaNum}>      <Max Pointers  :{intMaxPtrs}>\r\n<alpha:{cPtrAlpha}>         Filter        <Function Pointers:{rFilterPtr}><Pointers-to-Pointers:{rFilterP2P}>{rGroup}>\r\n<numeric:{cPtrNum}>{ptrGroup}>       Other settings<Do not search for pointers-to-pointers:{rSearchPtrOnly}>{rSearchGroup}>\r\n\r\n\r\n\"\"\", {\r\n                'cEChooser'       : Form.EmbeddedChooserControl(self.mod, swidth=131),\r\n                'ptrGroup'        : Form.ChkGroupControl((\"cPtrNonull\", \"cPtrAscii\", \"cPtrAsciiPrint\", \"cPtrUnicode\",'cPtrAlphaNum','cPtrAlpha','cPtrNum')),\r\n                'rGroup'          : Form.RadGroupControl((\"rFilterPtr\",\"rFilterP2P\") ),\r\n                'rSearchGroup'    : Form.ChkGroupControl((\"rSearchPtrOnly\",) ),\r\n                'strBadChars'     : Form.StringInput(swidth=70,tp=Form.FT_ASCII),\r\n                'radUnicode'      : Form.RadGroupControl((\"rUnicodeANSI\",\"rUnicodeOEM\",\"rUnicodeUTF7\",\"rUnicodeUTF8\")),\r\n                'intPtrOffset'    : Form.StringInput(tp=Form.FT_ASCII,value=\"0x0\", swidth=10),\r\n                'intP2POffset'    : Form.StringInput(tp=Form.FT_ASCII,value=\"0x0\", swidth=10),\r\n                'intMaxPtrs'      : Form.NumericInput(swidth=4,tp=Form.FT_DEC,value=0),\r\n                'FormChangeCb'    : Form.FormChangeCb(self.OnFormChange),\r\n            })\r\n\r\n        self.Compile()\r\n\r\n    def OnFormChange(self, fid):\r\n\r\n        # Form initialization\r\n        if fid == -1:\r\n            self.SetFocusedField(self.cEChooser)\r\n\r\n            # Preselect non-ASLR modules on startup if none were already specified\r\n            if self.select_list == None:\r\n                \r\n                self.select_list = list()\r\n                for i, m in enumerate(self.sploiter.modules):\r\n                    if m.ASLR == \"No\":\r\n                        self.select_list.append(i)\r\n\r\n            self.SetControlValue(self.cEChooser, self.select_list)\r\n\r\n        # Form OK pressed\r\n        elif fid == -2:\r\n            pass\r\n\r\n        return 1\r\n\r\n###############################################################################\r\n# Function Pointer Viewer\r\n\r\nclass PtrView(Choose2):\r\n    \"\"\"\r\n    Chooser class to display writable function pointers.\r\n    \"\"\"\r\n    def __init__(self, sploiter):\r\n\r\n        self.sploiter = sploiter\r\n\r\n        Choose2.__init__(self,\r\n                         \"Writeable function pointers\",\r\n                         [ [\"Pointer\",            13 | Choose2.CHCOL_HEX], \r\n                           [\"Offset\",              4 | Choose2.CHCOL_HEX], \r\n                           [\"Name\",               10 | Choose2.CHCOL_PLAIN],\r\n                           [\"Module\",             10 | Choose2.CHCOL_PLAIN],\r\n                           [\"Charset\",            12 | Choose2.CHCOL_PLAIN],\r\n                           [\"Caller Address\",     13 | Choose2.CHCOL_HEX], \r\n                           [\"Caller Name\",        10 | Choose2.CHCOL_PLAIN],\r\n                           [\"Instruction\",        15 | Choose2.CHCOL_PLAIN],\r\n                           [\"Ptr-to-Ptr\",         13 | Choose2.CHCOL_PLAIN],\r\n                           [\"Ptr-to-Ptr Offset\",   4 | Choose2.CHCOL_HEX], \r\n                           [\"Ptr-to-Ptr Charset\", 12 | Choose2.CHCOL_PLAIN],\r\n                         ],\r\n                         flags = Choose2.CH_MULTI_EDIT)\r\n\r\n        self.icon = 143\r\n\r\n        # Items for display and corresponding data\r\n        # NOTE: Could become desynchronized, so to avoid this\r\n        #       refresh the view after each change.\r\n        self.items = []\r\n\r\n        # Initialize/Refresh the view\r\n        self.refreshitems()\r\n\r\n        # Selected items\r\n        self.select_caller_breakpoint_list = list()\r\n\r\n        # Command callbacks\r\n        self.cmd_select_caller_breakpoint = None\r\n        self.cmd_jump_ptr = None\r\n        self.cmd_jump_p2p = None\r\n        self.cmd_jump_caller = None\r\n        self.cmd_export_csv  = None\r\n\r\n    def show(self):\r\n        # Attempt to open the view\r\n        if self.Show() < 0: return False\r\n\r\n        # Add extra context menu commands\r\n        # NOTE: Make sure you check for duplicates\r\n        if self.cmd_select_caller_breakpoint == None:\r\n            self.cmd_select_caller_breakpoint = self.AddCommand(\"Add breakpoint\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=120)\r\n\r\n        if self.cmd_jump_ptr == None:\r\n            self.cmd_jump_ptr = self.AddCommand(\"Jump to pointer\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=141)\r\n\r\n        if self.cmd_jump_p2p == None:\r\n            self.cmd_jump_p2p = self.AddCommand(\"Jump to pointer-to-pointer\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=142)\r\n\r\n        if self.cmd_jump_caller == None:\r\n            self.cmd_jump_caller = self.AddCommand(\"Jump to caller\", flags = idaapi.CHOOSER_POPUP_MENU | idaapi.CHOOSER_MULTI_SELECTION, icon=143)\r\n\r\n        if self.cmd_export_csv == None:\r\n            self.cmd_export_csv = self.AddCommand(\"Export as csv...\", flags = idaapi.CHOOSER_POPUP_MENU, icon=40)\r\n\r\n        return True\r\n\r\n    def refreshitems(self):\r\n        self.items = []\r\n\r\n        for ptr in self.sploiter.funcptr.ptrs:\r\n\r\n            self.items.append([ self.sploiter.addr_format % ptr.ptr_ea, \r\n                                hex(ptr.ptr_offset),\r\n                                ptr.name, \r\n                                ptr.module, \r\n                                \", \".join(ptr.ptr_charset),\r\n                                self.sploiter.addr_format % ptr.call_ea,\r\n                                ptr.call_name,\r\n                                ptr.insn_disas,      \r\n                                self.sploiter.addr_format % ptr.p2p_ea if ptr.p2p_ea else \"\",\r\n                                hex(ptr.p2p_offset) if ptr.p2p_ea else \"\",\r\n                                \", \".join(ptr.p2p_charset) if ptr.p2p_ea else \"\",                          \r\n                                ])\r\n\r\n    def OnCommand(self, n, cmd_id):\r\n\r\n        if cmd_id == self.cmd_select_caller_breakpoint:\r\n\r\n            # Empty selection\r\n            if n == -1:\r\n                pass                \r\n\r\n            # Selection start\r\n            elif n == -2:\r\n                self.select_caller_breakpoint_list = list()\r\n\r\n            # Selection end\r\n            elif n == -3:               \r\n\r\n                # Unique set of caller addresses\r\n                eas = set()\r\n\r\n                for i in self.select_caller_breakpoint_list:\r\n                    eas.add( self.sploiter.funcptr.ptrs[i].call_ea )\r\n\r\n                print \"[idasploiter] Settings %d breakpoints on selected caller addresses.\" % len(eas)\r\n\r\n                for ea in eas:\r\n                    # Set default software breakpoint\r\n                    idaapi.add_bpt(ea, 0, idaapi.BPT_DEFAULT)\r\n\r\n                self.select_caller_breakpoint_list = list()\r\n\r\n            # Selection number\r\n            else:\r\n                self.select_caller_breakpoint_list.append(n)\r\n\r\n        # Jump to Pointer address\r\n        elif cmd_id == self.cmd_jump_ptr:\r\n            if n >= 0 and self.sploiter.funcptr.ptrs[n].ptr_ea:\r\n                idaapi.jumpto( self.sploiter.funcptr.ptrs[n].ptr_ea )\r\n\r\n        # Jump to Pointer-to-Pointer address\r\n        elif cmd_id == self.cmd_jump_p2p:\r\n            if n >= 0 and self.sploiter.funcptr.ptrs[n].p2p_ea:\r\n                idaapi.jumpto( self.sploiter.funcptr.ptrs[n].p2p_ea )\r\n\r\n        # Jump to Caller address\r\n        elif cmd_id == self.cmd_jump_caller:\r\n            if n >= 0 and self.sploiter.funcptr.ptrs[n].call_ea:\r\n                idaapi.jumpto( self.sploiter.funcptr.ptrs[n].call_ea )\r\n\r\n        # Export CSV\r\n        elif cmd_id == self.cmd_export_csv:\r\n\r\n            file_name = idaapi.askfile_c(1, \"*.csv\", \"Please enter CSV file name\")\r\n            if file_name:\r\n                print \"[idasploiter] Exporting function pointers to %s\" % file_name\r\n                with open(file_name, 'wb') as csvfile:\r\n                    csvwriter = csv.writer(csvfile, delimiter=',',\r\n                                            quotechar='\"', quoting=csv.QUOTE_MINIMAL)\r\n                    csvwriter.writerow([\"Pointer\",\"Offset\",\"Name\",\"Module\",\"Charset\",\"Caller Address\",\"Caller Name\",\"Instruction\",\"Ptr-to-Ptr\",\"Ptr-to-Ptr Offset\",\"Ptr-to-Ptr Charset\"])\r\n                    for item in self.items:\r\n                        csvwriter.writerow(item)\r\n        return 1\r\n\r\n \r\n    def OnSelectLine(self, n):\r\n        idaapi.jumpto( int(self.items[n][0],16) )\r\n\r\n    def OnGetLine(self, n):\r\n        return self.items[n]\r\n\r\n    def OnClose(self):\r\n        self.cmd_select_caller_breakpoint = None\r\n        self.cmd_jump_ptr = None\r\n        self.cmd_jump_p2p = None\r\n        self.cmd_jump_caller = None\r\n        self.cmd_export_csv  = None\r\n\r\n    def OnGetSize(self):\r\n        return len(self.items)\r\n\r\n    def OnRefresh(self, n):\r\n        self.refreshitems()\r\n        return n\r\n\r\n    def OnActivate(self):\r\n        self.refreshitems()\r\n\r\n###############################################################################\r\n# Pattern UI\r\n###############################################################################\r\n\r\n###############################################################################\r\n# Pattern Create Form\r\n\r\nclass PatternCreateForm(Form):\r\n\r\n    def __init__(self, sploiter):\r\n\r\n        self.sploiter = sploiter\r\n        self.pattern_complete = \"\"\r\n\r\n        Form.__init__(self, \r\nr\"\"\"BUTTON YES NONE\r\nBUTTON CANCEL NONE\r\nCreate pattern\r\n{FormChangeCb}<:{strPattern}>\r\n<Size   :{intSize}>\r\nFormats<Regular:{rFmtReg}><Hex:{rFmtHex}><JavaScript:{rFmtJS}>{rGroup}>\r\nCharset<C4:{cC4}><##:{strC4}>\r\n       <C3:{cC3}><##:{strC3}>\r\n       <C2:{cC2}><##:{strC2}>\r\n       <C1:{cC1}>{cGroup}><##:{strC1}>\r\n\r\n{spacer}<Generate:{iButtonGenerate}>\r\n\"\"\", {\r\n            'spacer'          : Form.StringLabel(\"            \"),\r\n            'intSize'         : Form.NumericInput(swidth=30,tp=Form.FT_DEC,value=1000),\r\n            'iButtonGenerate' : Form.ButtonInput(self.OnButtonGenerate,swidth=5),\r\n            'rGroup'          : Form.RadGroupControl((\"rFmtReg\",\"rFmtHex\", \"rFmtJS\") ),\r\n            'cGroup'          : Form.ChkGroupControl((\"cC4\",\"cC3\",\"cC2\",\"cC1\")),\r\n            'strC4'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strC3'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strC2'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strC1'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strPattern'      : Form.MultiLineTextControl(text=\"\", width=400, flags = Form.MultiLineTextControl.TXTF_FIXEDFONT | Form.MultiLineTextControl.TXTF_SELECTED | Form.MultiLineTextControl.TXTF_READONLY),\r\n            'FormChangeCb'    : Form.FormChangeCb(self.OnFormChange),\r\n            })\r\n\r\n        self.Compile()\r\n\r\n    def OnFormChange(self, fid):\r\n\r\n        # Form initialization\r\n        if fid == -1:\r\n\r\n            # Set initial checkboxes for the classic metasploit 3-byte pattern\r\n            self.SetControlValue(self.cC4, False)\r\n            self.SetControlValue(self.cC3, True)\r\n            self.SetControlValue(self.cC2, True)\r\n            self.SetControlValue(self.cC1, True)\r\n\r\n            # Set initial charsets values\r\n            self.SetControlValue(self.strC4, self.sploiter.c4_list)\r\n            self.SetControlValue(self.strC3, self.sploiter.c3_list)\r\n            self.SetControlValue(self.strC2, self.sploiter.c2_list)\r\n            self.SetControlValue(self.strC1, self.sploiter.c1_list)\r\n\r\n        # Form OK pressed\r\n        elif fid == -2:\r\n            pass\r\n\r\n        return 1\r\n\r\n    def OnButtonGenerate(self, code=0):\r\n\r\n        size = self.GetControlValue(self.intSize) \r\n        print \"[idasploiter] Creating a pattern of size %d.\" % size\r\n\r\n        # Update global charset lists\r\n        self.sploiter.c4_list = self.GetControlValue(self.strC4)\r\n        self.sploiter.c3_list = self.GetControlValue(self.strC3)\r\n        self.sploiter.c2_list = self.GetControlValue(self.strC2)\r\n        self.sploiter.c1_list = self.GetControlValue(self.strC1)\r\n\r\n        # Generate pattern only using selected lists\r\n        self.update_complete_pattern(self.GetControlValue(self.cC4), self.GetControlValue(self.cC3), self.GetControlValue(self.cC2), self.GetControlValue(self.cC1))\r\n\r\n        pattern = self.pattern_create(size) \r\n\r\n        if pattern:\r\n\r\n            # Hex output\r\n            if self.GetControlValue(self.rGroup) == 1:\r\n                pattern = binascii.hexlify(pattern)\r\n\r\n            # JavaScript Unicode output\r\n            elif self.GetControlValue(self.rGroup) == 2:\r\n                \r\n                pattern_js = \"\"\r\n\r\n                # Number of WORDs in the pattern\r\n                num_words = len(pattern) / 2\r\n\r\n                # Chop off extra characters\r\n                num_extra = len(pattern) % 2\r\n                if num_extra:\r\n                    pattern = pattern[:-num_extra]\r\n\r\n                # Unpack individual WORDs from the pattern\r\n                words = struct.unpack(\"H\"*num_words, pattern)\r\n                for word in words:\r\n                    pattern_js += \"%%u%s\" % hex(word)\r\n\r\n                pattern = pattern_js\r\n\r\n            strPattern = idaapi.textctrl_info_t(text=pattern, flags = Form.MultiLineTextControl.TXTF_FIXEDFONT | Form.MultiLineTextControl.TXTF_SELECTED | Form.MultiLineTextControl.TXTF_READONLY)\r\n            self.SetControlValue(self.strPattern, strPattern )\r\n\r\n\r\n    def pattern_create(self, size):\r\n\r\n        # Make sure at least one custom charset was specified\r\n        if not len(self.pattern_complete):\r\n            idaapi.warning(\"Cannot generate an empty pattern.\")\r\n            return False\r\n\r\n        # Requested pattern size exceeds maximum allowed pattern size for the selected characterset\r\n        elif size > len(self.pattern_complete):\r\n            idaapi.warning(\"Requested size %d exceeds maximum unique pattern size %d.\" % (size, len(self.pattern_complete)))\r\n            return False\r\n\r\n        # Get a size substring from the complete pattern\r\n        else:\r\n            return self.pattern_complete[:size]\r\n\r\n    def update_complete_pattern(self, c4, c3, c2, c1):\r\n\r\n        c4_list = self.sploiter.c4_list if c4 else [\"\",]\r\n        c3_list = self.sploiter.c3_list if c3 else [\"\",]\r\n        c2_list = self.sploiter.c2_list if c2 else [\"\",]\r\n        c1_list = self.sploiter.c1_list if c1 else [\"\",]\r\n\r\n        # Generate complete pattern\r\n        # NOTE: Not as pretty as calculating offset based on positions, but\r\n        #       allows custom charactersets with varying positions\r\n        self.pattern_complete = \"\"\r\n\r\n        # Produce a cartesian product of all character lists and make a single string by flattening the list of lists\r\n        self.pattern_complete = ''.join([i for j in itertools.product(c4_list, c3_list, c2_list, c1_list) for i in j])\r\n\r\n\r\n###############################################################################\r\n# Pattern Offset Form\r\n\r\nclass PatternDetectForm(Form):\r\n\r\n    def __init__(self, sploiter, debugger = True):\r\n\r\n        self.sploiter = sploiter\r\n        self.debugger = debugger\r\n\r\n        self.pattern_complete = \"\"\r\n\r\n        form_dict = {\r\n            'spacer'         : Form.StringLabel(\"           \"),\r\n            'strPattern'      : Form.StringInput(tp=Form.FT_ASCII, swidth=17),\r\n            'strOffset'       : Form.StringInput(tp=Form.FT_ASCII, swidth=13),\r\n            'iButtonDetect'   : Form.ButtonInput(self.OnButtonDetect, swidth=5),\r\n            'rGroup'          : Form.RadGroupControl(('rFmtAuto', 'rFmtStr', 'rFmtAddr')),\r\n            'cGroup'          : Form.ChkGroupControl((\"cC4\",\"cC3\",\"cC2\",\"cC1\")),\r\n            'strC4'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strC3'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strC2'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'strC1'           : Form.StringInput(swidth=38,tp=Form.FT_ASCII),\r\n            'FormChangeCb'    : Form.FormChangeCb(self.OnFormChange),\r\n            }\r\n\r\n        reg_form = \"\"\r\n        self.reg_ctrls = list()\r\n\r\n        # Display register values when executed with a debugger running\r\n        if debugger:\r\n\r\n            # Populate register values and store form controls in a list\r\n            for reg_name in self.sploiter.reg_list:\r\n                reg_value = idc.GetRegValue(reg_name)\r\n                reg_value = self.sploiter.addr_format % reg_value\r\n\r\n                ctrlRegValue = Form.StringInput(tp=Form.FT_ASCII, value=reg_value,swidth=17)\r\n                form_dict[\"str%s\" % reg_name] = ctrlRegValue\r\n\r\n                ctrlRegOffset = Form.StringInput(tp=Form.FT_ASCII, swidth=13)\r\n                form_dict[\"str%sOffset\" % reg_name] = ctrlRegOffset\r\n\r\n                reg_form += \"  <%(reg)03s  :{str%(reg)s}><Offset:{str%(reg)sOffset}>\\n\" % {'reg': reg_name}\r\n\r\n                self.reg_ctrls.append( (ctrlRegValue,  ctrlRegOffset) )\r\n\r\n        Form.__init__(self, \r\nr\"\"\"BUTTON YES NONE\r\nBUTTON CANCEL NONE\r\nDetect pattern\r\n{FormChangeCb}%s<Pattern:{strPattern}><Offset:{strOffset}>\r\n\r\nFormats<Auto:{rFmtAuto}><Address:{rFmtAddr}><String:{rFmtStr}>{rGroup}>\r\nCharset<C4:{cC4}><:{strC4}>\r\n       <C3:{cC3}><:{strC3}>\r\n       <C2:{cC2}><:{strC2}>\r\n       <C1:{cC1}>{cGroup}><:{strC1}>\r\n\r\n{spacer}<Detect:{iButtonDetect}>\r\n\"\"\" % reg_form, form_dict)\r\n\r\n        self.Compile()\r\n\r\n    def OnFormChange(self, fid):\r\n\r\n        # Form initialization\r\n        if fid == -1:\r\n\r\n            # Set initial checkboxes for the classic metasploit 3-byte pattern\r\n            self.SetControlValue(self.cC4, False)\r\n            self.SetControlValue(self.cC3, True)\r\n            self.SetControlValue(self.cC2, True)\r\n            self.SetControlValue(self.cC1, True)\r\n\r\n            # Set initial charsets values\r\n            self.SetControlValue(self.strC4, self.sploiter.c4_list)\r\n            self.SetControlValue(self.strC3, self.sploiter.c3_list)\r\n            self.SetControlValue(self.strC2, self.sploiter.c2_list)\r\n            self.SetControlValue(self.strC1, self.sploiter.c1_list)\r\n\r\n            # NOTE: Trying to detect offset for registry values during\r\n            #       form initialization appears to be very slow and does\r\n            #       not provide an option for a user to specify a custom \r\n            #       characterset.\r\n\r\n        # Form OK pressed\r\n        elif fid == -2:\r\n            pass\r\n\r\n        return 1\r\n\r\n    def OnButtonDetect(self, code=0):\r\n\r\n        # Update global charset lists\r\n        self.sploiter.c4_list = self.GetControlValue(self.strC4)\r\n        self.sploiter.c3_list = self.GetControlValue(self.strC3)\r\n        self.sploiter.c2_list = self.GetControlValue(self.strC2)\r\n        self.sploiter.c1_list = self.GetControlValue(self.strC1)\r\n\r\n        # Generate pattern only using selected lists\r\n        self.update_complete_pattern(self.GetControlValue(self.cC4), self.GetControlValue(self.cC3), self.GetControlValue(self.cC2), self.GetControlValue(self.cC1))\r\n\r\n        for ctrlRegValue, ctrlRegOffset in self.reg_ctrls:\r\n            reg_value = self.GetControlValue(ctrlRegValue)\r\n            self.SetControlValue(ctrlRegOffset, self.verbalize_pattern(reg_value, address=True) )\r\n\r\n        pattern = self.GetControlValue(self.strPattern)\r\n\r\n        # Force address format\r\n        if self.GetControlValue(self.rFmtAddr):\r\n            self.SetControlValue(self.strOffset, self.verbalize_pattern(pattern, address=True) )\r\n\r\n        # Force string format\r\n        elif self.GetControlValue(self.rFmtStr):\r\n            self.SetControlValue(self.strOffset, self.verbalize_pattern(pattern, string=True) )\r\n\r\n        # Auto format\r\n        else:\r\n            self.SetControlValue(self.strOffset, self.verbalize_pattern(pattern) )\r\n\r\n    def verbalize_pattern(self, pattern, address=False, string=False):\r\n\r\n        # Forced address format\r\n        if address:\r\n\r\n            # Cleanup the pattern\r\n            pattern = pattern.replace(' ','')       # remove spaces\r\n            pattern = pattern.replace('\\\\x','')     # remove '\\x' prefixes\r\n            pattern = pattern.replace('0x','')      # remove '0x' prefixes\r\n\r\n            if self.sploiter.addr64 and len(pattern) == 8*2:\r\n                try:\r\n                    pattern = struct.pack(\"Q\", int(pattern, 16))\r\n                except Exception, e:\r\n                    return \"Invalid address\"\r\n\r\n            elif not self.sploiter.addr64 and len(pattern) == 4*2:\r\n                try:\r\n                    pattern = struct.pack(\"I\", int(pattern, 16))\r\n                except Exception, e:\r\n                    return \"Invalid address\"\r\n\r\n            else:\r\n                return \"Invalid address\"\r\n\r\n        # Forced string format\r\n        elif string:\r\n            pass\r\n\r\n        # Autodetect format\r\n        else:\r\n\r\n            # Cleanup the pattern\r\n            pattern = pattern.replace(' ','')       # remove spaces\r\n            pattern = pattern.replace('\\\\x','')     # remove '\\x' prefixes\r\n            pattern = pattern.replace('0x','')      # remove '0x' prefixes\r\n\r\n            # Attempt to detect and unpack pattern\r\n            if self.sploiter.addr64 and len(pattern) == 8*2:\r\n                try:\r\n                    pattern = struct.pack(\"Q\", int(pattern, 16))\r\n                except Exception, e:\r\n                    pass\r\n\r\n            elif not self.sploiter.addr64 and len(pattern) == 4*2:\r\n                try:\r\n                    pattern = struct.pack(\"I\", int(pattern, 16))\r\n                except Exception, e:\r\n                    pass\r\n\r\n        if len(pattern) > 0:\r\n            offset         = self.pattern_offset(pattern)\r\n            offset_reverse = self.pattern_offset(pattern[::-1])\r\n        else:\r\n            return \"Blank pattern\"\r\n\r\n        if offset >= 0:\r\n            return \"%d\" % offset\r\n        elif offset_reverse >= 0:\r\n            return \"%d (reverse)\" % offset_reverse\r\n        else:\r\n            return \"Not detected\"\r\n\r\n    def pattern_offset(self, pattern):\r\n\r\n        offset = -1\r\n\r\n        # Make sure at least one custom charset was specified\r\n        if not len(self.pattern_complete):\r\n            idaapi.warning(\"Cannot detect an empty pattern.\")\r\n            return offset\r\n\r\n        # Locate the pattern\r\n        if pattern in self.pattern_complete:\r\n            offset = self.pattern_complete.index(pattern)\r\n\r\n        return offset\r\n\r\n    def update_complete_pattern(self, c4, c3, c2, c1):\r\n\r\n        c4_list = self.sploiter.c4_list if c4 else [\"\",]\r\n        c3_list = self.sploiter.c3_list if c3 else [\"\",]\r\n        c2_list = self.sploiter.c2_list if c2 else [\"\",]\r\n        c1_list = self.sploiter.c1_list if c1 else [\"\",]\r\n\r\n        # Generate complete pattern\r\n        # NOTE: Not as pretty as calculating offset based on positions, but\r\n        #       allows custom character sets with varying positions\r\n        self.pattern_complete = \"\"\r\n\r\n        # Produce a cartesian product of all character lists and make a single string by flattening the list of lists\r\n        self.pattern_complete = ''.join([i for j in itertools.product(c4_list, c3_list, c2_list, c1_list) for i in j])\r\n\r\n###############################################################################\r\n# Compare UI\r\n###############################################################################\r\n\r\n###############################################################################\r\n# Compare Form\r\n\r\nclass CompareForm(Form):\r\n\r\n    def __init__(self, sploiter, debugger = True):\r\n\r\n        self.sploiter = sploiter\r\n        self.debugger = debugger\r\n\r\n        Form.__init__(self, \r\nr\"\"\"BUTTON YES NONE\r\nBUTTON CANCEL NONE\r\nCompare file to memory\r\n{FormChangeCb}<File     :{impFile}>\r\n<Memory   :{intAddr}>\r\n\r\n<:{strCompare}>\r\n\r\n<Bad Chars:{strBadChars}>\r\n<Mem Holes:{strMemHoles}>\r\n\r\n{spacer}<Compare:{iButtonCompare}>\r\n\"\"\", {\r\n            'spacer'        : Form.StringLabel(\"                                \"),\r\n            'impFile'        : Form.FileInput(swidth=62, open=True),\r\n            'intAddr'        : Form.NumericInput(swidth=62, tp=Form.FT_ADDR, value=idaapi.get_screen_ea()),\r\n            'strCompare'     : Form.MultiLineTextControl(text=\"\", swidth=72, flags = Form.MultiLineTextControl.TXTF_FIXEDFONT | Form.MultiLineTextControl.TXTF_READONLY),\r\n            'strBadChars'    : Form.StringInput(swidth=62,tp=Form.FT_ASCII),\r\n            'strMemHoles'    : Form.StringInput(swidth=62,tp=Form.FT_ASCII),\r\n            'iButtonCompare' : Form.ButtonInput(self.OnButtonCompare,),\r\n            'FormChangeCb'   : Form.FormChangeCb(self.OnFormChange),\r\n            })\r\n\r\n        self.Compile()\r\n\r\n    def OnFormChange(self, fid):\r\n\r\n        # Form initialization\r\n        if fid == -1:\r\n            pass\r\n\r\n        # Form OK pressed\r\n        elif fid == -2:\r\n            pass\r\n\r\n        return 1\r\n\r\n    def OnButtonCompare(self, code=0):\r\n        \r\n        #######################################################################\r\n        # Read file into buffer\r\n        file_name = self.GetControlValue(self.impFile)\r\n\r\n        # Verify file name was provided\r\n        if not len(file_name):\r\n            idaapi.warning(\"Please provide file name.\")\r\n            return\r\n\r\n        # Attempt to read the file\r\n        print \"[idasploiter] Reading file %s\" % file_name\r\n        \r\n        try:\r\n            f = open(file_name,'rb')\r\n        except Exception, e:\r\n            idaapi.warning(\"File I/O error({0}): {1}.\".format(e.errno, e.strerror) )\r\n            return\r\n        else:\r\n            file_buf = f.read()\r\n            f.close()\r\n\r\n        # Check file content\r\n        if not len(file_buf) > 0:\r\n            idaapi.warning(\"Provided file was blank.\")\r\n            return\r\n\r\n        # 64k ought to be enough for anybody =)\r\n        elif len(file_buf) > 0xffff:\r\n            idaapi.warning(\"File is too big.\")\r\n            return\r\n\r\n        # Covert file bytes into printable hex view\r\n        file_buf_str = \" \".join([\"%02x\" % ord(b) for b in file_buf])\r\n        file_buf_list = textwrap.wrap(file_buf_str, 48)\r\n\r\n        #######################################################################\r\n        # Read memory into buffer and mark non-matching bytes\r\n        address = self.GetControlValue(self.intAddr)\r\n\r\n        print \"[idasploiter] Reading %d bytes from %s.\" % ( len(file_buf), self.sploiter.addr_format % address)\r\n\r\n        if self.debugger:\r\n            mem_buf = read_module_memory(address, len(file_buf))\r\n        else:\r\n            mem_buf = idaapi.get_many_bytes(address, len(file_buf))\r\n\r\n        if not mem_buf:\r\n            idaapi.warning(\"Could not read memory.\")\r\n            return\r\n\r\n        # Convert memory bytes into printable hex view\r\n        mem_buf_str = \"\"\r\n\r\n        # Badchars tracking\r\n        badchars = list()\r\n        badchars_nonseq = set()\r\n        badchars_hole = list()\r\n\r\n        # Locate all of the non-sequential badchars. The assumption is that\r\n        # after the first badchar (e.g. 0x0A) the rest may be corrupted.\r\n        for i, b in enumerate(file_buf):\r\n            if file_buf[i] == mem_buf[i]:\r\n                mem_buf_str+= \".. \"\r\n\r\n            else:\r\n                mem_buf_str+= \"%02x \" % ord( mem_buf[i])\r\n\r\n            # Do differential processing if the two bytes are not the same or\r\n            # if the matching byte is in the bad characters list\r\n\r\n            if file_buf[i] != mem_buf[i] or \"%02x\" % ord(file_buf[i]) in badchars_nonseq:\r\n\r\n                ###############################################################\r\n                # Memory holes\r\n\r\n                # Check if the badchar appears anywhere else in memory to\r\n                # detect positional holes. If this is the first discrepancy\r\n                # then it is likely it is a badchar (e.g. 0x00, 0x0a, 0x0d)\r\n\r\n                if len(badchars_hole):\r\n                    hole_i, hole_size = badchars_hole[-1]\r\n\r\n                    # Continuation of a previously discovered hole\r\n                    if i == hole_i + hole_size:\r\n                        badchars_hole[-1] = (hole_i, hole_size + 1)\r\n\r\n                    # New hole discovered\r\n                    else:\r\n                        badchars_hole.append( (i,1) )\r\n\r\n                # New hole discovered\r\n                else:\r\n                    badchars_hole.append( (i,1) )\r\n\r\n                ###############################################################\r\n                # Bad characters\r\n\r\n                # Check if previous byte in the file is already a badchar, so\r\n                # this new discrepancy doesn't matter:\r\n\r\n                if not \"%02x\" % ord(file_buf[i-1]) in  badchars_nonseq:\r\n\r\n                    # Skip sequential corruption\r\n                    if len(badchars_nonseq):\r\n                        bad_i, bad_b = badchars[-1]\r\n\r\n                        # Check if the previous byte was also corrupted\r\n                        # indicating a sequential corruption\r\n                        if i - 1 != bad_i:\r\n                            badchars_nonseq.add( \"%02x\" % ord(b) )\r\n\r\n                    else:                      \r\n                        badchars_nonseq.add( \"%02x\" % ord(b) )\r\n\r\n                # Store badchars in a list\r\n                badchars.append( (i,b) )\r\n\r\n\r\n        mem_buf_list = textwrap.wrap(mem_buf_str, 48)\r\n\r\n        if len(badchars) == 0:\r\n            self.SetControlValue(self.strBadChars, \"Identical.\")  \r\n        elif len(badchars) == len(file_buf):\r\n            self.SetControlValue(self.strBadChars, \"Completely different.\")          \r\n        else:\r\n            self.SetControlValue(self.strBadChars, \" \".join( sorted(badchars_nonseq) ) )\r\n            self.SetControlValue(self.strMemHoles, \", \".join( [ \"0x%02X: %d byte(s)\" % h for h in badchars_hole ]  ) )\r\n\r\n        #######################################################################\r\n        # Populate the text box\r\n\r\n        buf_formatted = \"      00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F\\n\\n\"\r\n        for i in range( len(file_buf_list) ):\r\n\r\n            file_line = file_buf_list[i].ljust(48)\r\n            file_line = file_line[:23]+\" \"+file_line[23:]\r\n\r\n            mem_line = mem_buf_list[i].ljust(48)\r\n            mem_line = mem_line[:23]+\" \"+mem_line[23:]\r\n\r\n            buf_formatted += \"%04X  %s  F\\n      %s  M\\n\\n\" % (i*0x10, file_line, mem_line)\r\n\r\n        strCompare = idaapi.textctrl_info_t(text=buf_formatted, flags = Form.MultiLineTextControl.TXTF_FIXEDFONT | Form.MultiLineTextControl.TXTF_READONLY)\r\n        self.SetControlValue(self.strCompare, strCompare)\r\n\r\n###############################################################################\r\n# Plugin Manager\r\n###############################################################################\r\n\r\nclass SploitManager():\r\n    \"\"\" Class that manages GUI forms and exploitation methods of the plugin. \"\"\"\r\n    \r\n    def __init__(self):\r\n\r\n        # Import plugins in function scope to avoid circular dependencies from importing in global scope.\r\n        from idasploiter_x86 import x86_Sploiter\r\n        from idasploiter_ppc import ppc_Sploiter\r\n\r\n        self.addmenu_item_ctxs = list()\r\n\r\n        # Initialize sploiter class based on architecture type.\r\n        if idaapi.ph.id == idaapi.PLFM_386:\r\n            self.sploiter = x86_Sploiter()\r\n        elif idaapi.ph.id == idaapi.PLFM_PPC:\r\n            self.sploiter = ppc_Sploiter()\r\n        else:\r\n            self.sploiter = None\r\n            print(\"Current processor type is not supported!\")\r\n\r\n\r\n    def is_architecture_supported(self):\r\n        return False if self.sploiter is None else True\r\n\r\n\r\n    ###########################################################################\r\n    # Menu Items\r\n    def add_menu_item_helper(self, menupath, name, hotkey, flags, pyfunc, args):\r\n\r\n        # add menu item and report on errors\r\n        addmenu_item_ctx = idaapi.add_menu_item(menupath, name, hotkey, flags, pyfunc, args)\r\n        if addmenu_item_ctx is None:\r\n            return 1\r\n        else:\r\n            self.addmenu_item_ctxs.append(addmenu_item_ctx)\r\n            return 0\r\n\r\n    def add_menu_items(self):\r\n        if self.add_menu_item_helper(\"View/Open subviews/Segments\", \"Modules\", \"Shift+F6\", 0, self.show_modules_view, None): return 1\r\n\r\n        # Check if this feature is supported or not.\r\n        if self.sploiter.is_func_ptr_supported():\r\n            if self.add_menu_item_helper(\"Search/all error operands\", \"function pointers...\", \"Alt+f\", 1, self.show_funcptr_view, None): return 1\r\n\r\n        if self.add_menu_item_helper(\"Search/all error operands\", \"gadgets...\", \"Alt+r\", 1, self.show_rop_view, None): return 1\r\n\r\n        if self.add_menu_item_helper(\"Edit/Begin selection\", \"Create pattern...\", \"Shift+c\", 0, self.show_pattern_create, None): return 1\r\n        if self.add_menu_item_helper(\"Edit/Begin selection\", \"Detect pattern...\", \"Shift+d\", 0, self.show_pattern_detect, None): return 1\r\n        if self.add_menu_item_helper(\"Edit/Begin selection\", \"Compare file to memory...\", \"Shift+f\", 0, self.show_compare, None): return 1\r\n        \r\n        return 0\r\n\r\n    def del_menu_items(self):\r\n        for addmenu_item_ctx in self.addmenu_item_ctxs:\r\n            result = idaapi.del_menu_item(addmenu_item_ctx)\r\n\r\n    ###########################################################################\r\n    # Utility Functions\r\n\r\n    # Check debugger is ready for querying\r\n    def check_debugger(self):\r\n        if idaapi.dbg_can_query() and idaapi.get_process_state() < 0:\r\n            return True\r\n        else:\r\n            return False\r\n\r\n    ###########################################################################\r\n    # View Callbacks\r\n    \r\n    # Modules View\r\n    def show_modules_view(self):\r\n        self.sploiter.process_modules()\r\n        self.sploiter.show_modules_view()\r\n            \r\n\r\n    # ROP View\r\n    def show_rop_view(self):\r\n        self.sploiter.process_modules()\r\n        self.sploiter.process_rop()\r\n            \r\n\r\n    # Function Pointer View\r\n    def show_funcptr_view(self):\r\n        self.sploiter.process_modules()\r\n        self.sploiter.process_funcptr()\r\n\r\n    # Create Pattern Form\r\n    def show_pattern_create(self):\r\n        self.sploiter.pattern_create()\r\n\r\n    # Detect Pattern Form\r\n    def show_pattern_detect(self):\r\n\r\n        # Debugger Version\r\n        if self.check_debugger():\r\n            self.sploiter.pattern_detect()\r\n\r\n        # Static Version\r\n        else:\r\n            self.sploiter.pattern_detect(debugger=False)\r\n\r\n    # Compare File to Memory Form\r\n    def show_compare(self):\r\n\r\n        # Debugger Version\r\n        if self.check_debugger():\r\n            self.sploiter.process_compare()\r\n\r\n        # Static Version\r\n        else:\r\n            self.sploiter.process_compare(debugger=False)\r\n\r\n\r\n###############################################################################\r\n\r\nclass idasploiter_t(plugin_t):\r\n\r\n    flags = idaapi.PLUGIN_PROC\r\n    comment = \"Exploit development and vulnerability research toolkit.\"\r\n    help = \"Exploit development and vulnerability research toolkit.\"\r\n    wanted_name = \"IDA Sploiter\"\r\n    wanted_hotkey = \"\"\r\n\r\n    def init(self):\r\n        global idasploiter_manager\r\n\r\n        if 'idasploiter_manager' in globals().keys():\r\n\r\n            idasploiter_manager.del_menu_items()\r\n            del idasploiter_manager\r\n\r\n        # Initialize the sploit manager.\r\n        idasploiter_manager = SploitManager()\r\n        if idasploiter_manager.is_architecture_supported() is False:\r\n            return idaapi.PLUGIN_SKIP\r\n\t\t\t\r\n\t\t# Add menu items.\r\n        if idasploiter_manager.add_menu_items():\r\n            print \"Failed to initialize IDA Sploiter.\"\r\n\r\n            idasploiter_manager.del_menu_items()\r\n            del idasploiter_manager\r\n\r\n            return idaapi.PLUGIN_SKIP\r\n        else:\r\n            print(\"Initialized IDA Sploiter v%s (c) Peter Kacherginsky <iphelix@thesprawl.org>\" % IDASPLOITER_VERSION)\r\n\r\n        return idaapi.PLUGIN_KEEP\r\n\r\n    def run(self, arg):\r\n        pass\r\n\r\n    def term(self):\r\n        global idasploiter_manager\r\n\r\n        if 'idasploiter_manager' in globals().keys():\r\n\r\n            idasploiter_manager.del_menu_items()\r\n            del idasploiter_manager\r\n\r\ndef PLUGIN_ENTRY():\r\n    return idasploiter_t()\r\n\r\n###############################################################################\r\n# Script / Testing\r\n###############################################################################\r\n\r\ndef idasploiter_main():\r\n    global idasploiter_manager\r\n\r\n    if 'idasploiter_manager' in globals():\r\n        idasploiter_manager.del_menu_items()\r\n        del idasploiter_manager\r\n\r\n    idasploiter_manager = SploitManager()\r\n    idasploiter_manager.add_menu_items()\r\n\r\n    sploiter = idasploiter_manager.sploiter\r\n\r\nif __name__ == '__main__':\r\n    #idasploiter_main()\r\n    pass"
  },
  {
    "path": "idasploiter_ppc.py",
    "content": "#!/usr/bin/env python\r\n#\r\n# IDA Sploiter is an exploit development and vulnerability research environment\r\n# implemented as a plugin for Hex-Ray's IDA Pro disassembler.\r\n\r\n# Copyright (C) 2014 Peter Kacherginsky\r\n# All rights reserved.\r\n#\r\n# Redistribution and use in source and binary forms, with or without\r\n# modification, are permitted provided that the following conditions are met:\r\n#\r\n# 1. Redistributions of source code must retain the above copyright notice, this\r\n#    list of conditions and the following disclaimer.\r\n# 2. Redistributions in binary form must reproduce the above copyright notice,\r\n#    this list of conditions and the following disclaimer in the documentation\r\n#    and/or other materials provided with the distribution.\r\n# 3. Neither the name of the copyright holder nor the names of its contributors\r\n#    may be used to endorse or promote products derived from this software without\r\n#    specific prior written permission.\r\n#\r\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r\n# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n# Performance profiling\r\nimport cProfile\r\nimport pstats\r\n\r\n# IDA Sploiter\r\nfrom idasploiter import FuncPtr, Gadget, Ptr, Rop, read_module_memory, Sploiter\r\n\r\n# IDA libraries\r\nimport idaapi\r\nimport idautils\r\nimport idc\r\nfrom idaapi import Form, Choose2, plugin_t\r\n\r\n# Python libraries\r\nimport os\r\nimport binascii\r\nimport string\r\nimport textwrap\r\nimport copy\r\nimport csv\r\nimport itertools\r\nimport struct\r\n\r\nfrom struct import pack, unpack\r\nfrom ctypes import *\r\n\r\n\r\n###############################################################################\r\n# ROP Search Engine\r\n\r\nclass ppc_Rop(Rop):\r\n\r\n    def __init__(self, sploiter):\r\n        \r\n        Rop.__init__(self, sploiter)\r\n\r\n        # Extra bytes to read to ensure correct decoding of\r\n        # BLR instructions.\r\n        self.dbg_read_extra = 4\r\n\r\n        self.insn_arithmetic_ops = [\"neg\", \"add\",\"addc\",\"adde\",\"addi\",\"addic\",\"addic.\",\"addis\",\"addme\",\"addze\",\"divw\",\"divw.\",\"divwo\",\"divwo.\",\"divwu\",\"divwu.\",\"divwuo\",\"divwuo.\",\"mulhw\",\"mulhw.\",\"mulhwu\",\"mulhwu.\",\"mulli\",\"mullw\",\"mullw.\",\"mullwo\",\"mullwo.\",\r\n\t\t\t\t\t\t\t\t\t\"subf\",\"subf.\",\"subfo\",\"subfo.\",\"sub\",\"subfc\",\"subfc.\",\"subfco\",\"subfco.\",\"subc\",\"subfe\",\"subfe.\",\"subfeo\",\"subfeo.\",\"subfic\",\"subfme\",\"subfme.\",\"subfmeo\",\"subfmeo.\",\"subfzo\",\"subfze.\",\"subfzeo\",\"subfzeo.\"]\r\n        self.insn_bit_ops = [\"neg\",\"and\",\"andc\",\"andi\",\"andis\",\"or\",\"orc\",\"ori\",\"oris\",\"nand\",\"nor\",\"xor\",\"xori\",\"xoris\",\"slw\",\"srw\",\"sraw\",\"srawi\",\"rlwimi\",\"rlwinm\",\"rlwnm\",\"rldicr\"]\r\n\r\n    def get_o_reg_name(self, insn, n):\r\n\r\n        reg_num = insn.Operands[n].reg\r\n        reg_name = self.regnames[reg_num]\r\n\r\n        return reg_name\r\n\r\n    def search_retns(self):\r\n\r\n        if not self.debug: print(\"found %d modules\" % len(self.modules))\r\n        for m in self.modules:\r\n\r\n            # Iterate over segments in the module\r\n            # BUG: Iterating over all loaded segments is more stable than looking up by address\r\n            if not self.debug: print(\"found %d segments\" % idaapi.get_segm_qty())\r\n            for n in xrange(idaapi.get_segm_qty()):\r\n                seg = idaapi.getnseg(n)\r\n\r\n                # Locate executable segments in a selected modules\r\n                # NOTE: Each module may have multiple executable segments\r\n                if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size):\r\n                    # If the debugger is attached then we can check if the segment is executable, else\r\n                    # just check if it is code or not.\r\n                    if idaapi.dbg_can_query() and idaapi.get_process_state() < 0:\r\n                        if seg.perm & idaapi.SEGPERM_EXEC == 0:\r\n                            continue\r\n                    elif seg.type & idaapi.SEG_CODE == 0:\r\n                        continue\r\n\r\n                    #######################################################\r\n                    # Search for ROP gadgets\r\n                    if self.searchRop:\r\n\r\n                        #Search all instances of BLR\r\n                        ea = seg.startEA\r\n                        while True:\r\n                            ea = idaapi.find_binary(ea + 1, seg.endEA, \"4E 80 00 20\", 16, idaapi.SEARCH_DOWN)\r\n                            if ea == idaapi.BADADDR: break\r\n\r\n                            self.retns.append((ea, m.file))\r\n\r\n                        # Search all instances of BTCTR\r\n                        ea = seg.startEA\r\n                        while True:\r\n                            ea = idaapi.find_binary(ea + 1, seg.endEA, \"4E 80 04 20\", 16, idaapi.SEARCH_DOWN)\r\n                            if ea == idaapi.BADADDR: break\r\n\r\n                            self.retns.append((ea, m.file))\r\n\r\n                        # Search all instances of BTCTRL\r\n                        ea = seg.startEA\r\n                        while True:\r\n                            ea = idaapi.find_binary(ea + 1, seg.endEA, \"4E 80 04 21\", 16, idaapi.SEARCH_DOWN)\r\n                            if ea == idaapi.BADADDR: break\r\n\r\n                            self.retns.append((ea, m.file))\r\n\r\n    def search_gadgets(self):\r\n\r\n        count_total = len(self.retns)\r\n        count_notify = 0\r\n        count_curr  = 0\r\n\r\n        # BUG: A separate flag is used to track user canceling the search,\r\n        #      because multiple calls to idaapi.wasBreak() do not properly\r\n        #      detect cancellations.\r\n        breakFlag = False\r\n\r\n        # Show wait dialog\r\n        if not self.debug: idaapi.show_wait_box(\"Searching gadgets: 00%%%%\")\r\n\r\n        print(\"found %s retns\" % len(self.retns))\r\n        for (ea_end, module) in self.retns:\r\n\r\n            # Flush the gadgets cache for each new retn pointer\r\n            self.gadgets_cache = dict()\r\n\r\n            # Flush memory cache for each new retn pointer\r\n            self.dbg_mem_cache = None\r\n\r\n            # CACHE: It is faster to read as much memory in one blob than to make incremental reads backwards.\r\n            #        Try to read and cache self.maxRopSize instructions back. In cases where it is not possible,\r\n            #        then simply try to read the largest chunk.\r\n            \r\n            # NOTE: Read a bit extra to cover correct decoding of RETN and RETN imm16 instructions.\r\n\t\t\t\r\n            self.dbg_mem_cache = read_module_memory(ea_end - (self.maxRopSize * 4), (self.maxRopSize * 4) + self.dbg_read_extra)\r\n\r\n            # Check to make sure we have actual data to work with.\r\n            if self.dbg_mem_cache == None:\r\n                continue\r\n\r\n            # Search all possible gadgets up to maxoffset bytes back\r\n            # NOTE: try all byte combinations to capture longer/more instructions\r\n            #       even with bad bytes in the middle.\r\n            for i in range(1, self.maxRopSize + 1):\r\n\r\n                ea = ea_end - (i * 4)\r\n\r\n                # Get pointer charset\r\n                ptr_charset = self.sploiter.get_ptr_charset(ea)\r\n\r\n                # Filter the pointer\r\n                if ptr_charset == None:                                    continue\r\n                if self.ptrNonull     and not \"nonull\"     in ptr_charset: continue\r\n                if self.ptrUnicode    and not \"unicode\"    in ptr_charset: continue\r\n                if self.ptrAscii      and not \"ascii\"      in ptr_charset: continue\r\n                if self.ptrAsciiPrint and not \"asciiprint\" in ptr_charset: continue\r\n                if self.ptrAlphaNum   and not \"alphanum\"   in ptr_charset: continue\r\n                if self.ptrNum        and not \"numeric\"    in ptr_charset: continue\r\n                if self.ptrAlpha      and not \"alpha\"      in ptr_charset: continue\r\n\r\n                # Try to build a gadget at the pointer\r\n                gadget = self.build_gadget(ea, ea_end)\r\n\r\n                # Successfully built the gadget\r\n                if gadget:\r\n\r\n                    # Populate gadget object with more data\r\n                    gadget.address = ea\r\n                    gadget.module = module\r\n                    gadget.ptr_charset = ptr_charset\r\n\r\n                    # Filter gadgets with too many instruction\r\n                    if gadget.size > self.maxRopSize:\r\n                        break\r\n\r\n                    # Append newly built gadget\r\n                    self.gadgets.append(gadget)\r\n                    self.gadgets_cache[ea] = gadget\r\n\r\n                    # Exceeded maximum number of gadgets\r\n                    if self.maxRops and len(self.gadgets) >= self.maxRops:\r\n                        breakFlag = True\r\n                        print \"[idasploiter] Maximum number of gadgets exceeded.\"\r\n                        break\r\n                else:\r\n                    self.gadgets_cache[ea] = None\r\n\r\n                if breakFlag or idaapi.wasBreak():\r\n                    breakFlag = True\r\n                    break\r\n\r\n            # Canceled\r\n            # NOTE: Only works when started from GUI not script.\r\n            if breakFlag or idaapi.wasBreak():\r\n                breakFlag = True\r\n                print \"[idasploiter] Canceled.\"\r\n                break\r\n\r\n            # Progress report\r\n            if not self.debug and count_curr >= count_notify:\r\n                # NOTE: Need to use %%%% to escape both Python and IDA's format strings\r\n                idaapi.replace_wait_box(\"Searching gadgets: %02d%%%%\" % (count_curr * 100/count_total))\r\n\r\n                count_notify += 0.10 * count_total\r\n\r\n            count_curr += 1\r\n\r\n        print \"[idasploiter] Found %d gadgets.\" % len(self.gadgets)\r\n        if not self.debug: idaapi.hide_wait_box()\r\n\r\n\r\n    # Attempt to build a gadget at the provided start address\r\n    # by verifying it properly terminates at the expected RETN.\r\n    def build_gadget(self, ea, ea_end):\r\n\r\n        instructions  = list()\r\n        chg_registers = set()\r\n        use_registers = set()\r\n        operations    = set()\r\n        pivot         = 0\r\n\r\n        # Process each instruction in the gadget\r\n        while ea <= ea_end:\r\n\r\n            ###################################################################\r\n            # Gadget Level Cache:\r\n            #\r\n            # Locate a gadget (failed or built) starting at this address.\r\n            # If one is located, then we don't need to process any further\r\n            # instructions and just get necessary data from the cached\r\n            # gadget to never have to process the same address twice.\r\n            if ea in self.gadgets_cache:\r\n\r\n                # Check if the gadget was build successfully\r\n                gadget_cache = self.gadgets_cache[ea]\r\n                \r\n                # Build the reset of the gadget from cache\r\n                if gadget_cache:\r\n\r\n                    for insn in gadget_cache.instructions:\r\n                        instructions.append(insn)\r\n\r\n                    for reg in gadget_cache.chg_registers:\r\n                        chg_registers.add(reg)\r\n\r\n                    for reg in gadget_cache.use_registers:\r\n                        use_registers.add(reg)\r\n\r\n                    for op in gadget_cache.operations:\r\n                        operations.add(op)\r\n\r\n                    pivot += gadget_cache.pivot\r\n\r\n                    gadget = Gadget(instructions, pivot, operations, chg_registers, use_registers)\r\n                    return gadget\r\n\r\n                # Previous attempt to build gadget at this address failed\r\n                else:\r\n                    return None\r\n\r\n            # Process new instruction\r\n            else:\r\n\r\n                # Instruction length\r\n                # NOTE: decode_insn also sets global idaapi.cmd\r\n                #       which contains insn_t structure\r\n                insn_size = idaapi.decode_insn(ea)\r\n\r\n                # Check successful decoding of the instruction\r\n                if insn_size:\r\n\r\n                    ###############################################################\r\n                    # Instruction Level Cache\r\n                    #\r\n                    # Most instructions are repetitive so we can just cache\r\n                    # unique byte combinations to avoid costly decoding more\r\n                    # than once\r\n                    \r\n                    # Read instruction from memory cache\r\n                    dbg_mem_offset = ea - (ea_end - (len(self.dbg_mem_cache) - self.dbg_read_extra))\r\n                    dbg_mem = self.dbg_mem_cache[dbg_mem_offset:dbg_mem_offset + insn_size]\r\n\r\n                    # Create instruction cache if it doesn't already exist\r\n                    if not dbg_mem in self.insn_cache:\r\n\r\n                        ###########################################################\r\n                        # Decode instruction\r\n                        ###########################################################\r\n\r\n                        # Get global insn_t structure describing the instruction\r\n                        # NOTE: copy() is expensive, so we keep this single-threaded\r\n                        insn = idaapi.cmd\r\n\r\n                        #######################################################\r\n                        # Decode and Cache instruction characteristics\r\n                        self.insn_cache[dbg_mem] = self.decode_instruction(insn, ea, ea_end)\r\n\r\n                    ##################################################################\r\n                    # Retrieve cached instruction and apply it to the gadget\r\n\r\n                    # Check that cached instruction contains valid data\r\n                    if self.insn_cache[dbg_mem]:\r\n\r\n                        # Retrieve basic instruction characteristics\r\n                        insn_mnem = self.insn_cache[dbg_mem][\"insn_mnem\"]\r\n                        insn_disas = self.insn_cache[dbg_mem][\"insn_disas\"]\r\n                        instructions.append(insn_disas)\r\n\r\n                        # Check if we found an instruction that would change the instruction pointer\r\n                        if insn_mnem == \"blr\" or insn_mnem == \"bctr\" or insn_mnem == \"bctrl\":\r\n\r\n                            # RETN at the expected address\r\n                            if ea == ea_end:\r\n                                gadget = Gadget(instructions, pivot, operations, chg_registers, use_registers)\r\n                                return gadget\r\n\r\n                            # RETN at an unexpected address\r\n                            else:\r\n                                return None\r\n\r\n                        #######################################################\r\n                        # Add instruction instruction characteristics to the gadget\r\n                        else:\r\n\r\n                            for reg in self.insn_cache[dbg_mem][\"insn_chg_registers\"]:\r\n                                chg_registers.add(reg)\r\n\r\n                            for reg in self.insn_cache[dbg_mem][\"insn_use_registers\"]:\r\n                                use_registers.add(reg)\r\n\r\n                            for op in self.insn_cache[dbg_mem][\"insn_operations\"]:\r\n                                operations.add(op)\r\n\r\n                            pivot += self.insn_cache[dbg_mem][\"insn_pivot\"]\r\n\r\n                    # Previous attempt to decode the instruction invalidated the gadget\r\n                    else:\r\n                        return None\r\n                        \r\n                    ###############################################################\r\n                    # Next instruction\r\n                    # NOTE: This is outside cache\r\n                    ea += insn_size\r\n\r\n                ###################################################################\r\n                # Failed decoding of the instruction\r\n                # NOTE: Gadgets may have bad instructions in the middle which\r\n                #       can be tolerated as long as we can find a useful instruction\r\n                #       further out.\r\n                else:\r\n                    # Invalidate the gadget\r\n                    return None\r\n\r\n        # Failed to build a gadget, because RETN instruction was not found\r\n        return None\r\n\r\n    ###############################################################\r\n    # Decode instruction\r\n\r\n    def decode_instruction(self, insn, ea, ea_end):\r\n\r\n        # Instruction specific characteristics\r\n        insn_chg_registers = set()\r\n        insn_use_registers = set()\r\n        insn_operations = set()\r\n        insn_pivot = 0\r\n\r\n        # Instruction feature\r\n        #\r\n        # instruc_t.feature\r\n        #\r\n        # CF_STOP = 0x00001 #  Instruction doesn't pass execution to the next instruction\r\n        # CF_CALL = 0x00002 #  CALL instruction (should make a procedure here)\r\n        # CF_CHG1 = 0x00004 #  The instruction modifies the first operand\r\n        # CF_CHG2 = 0x00008 #  The instruction modifies the second operand\r\n        # CF_CHG3 = 0x00010 #  The instruction modifies the third operand\r\n        # CF_CHG4 = 0x00020 #  The instruction modifies 4 operand\r\n        # CF_CHG5 = 0x00040 #  The instruction modifies 5 operand\r\n        # CF_CHG6 = 0x00080 #  The instruction modifies 6 operand\r\n        # CF_USE1 = 0x00100 #  The instruction uses value of the first operand\r\n        # CF_USE2 = 0x00200 #  The instruction uses value of the second operand\r\n        # CF_USE3 = 0x00400 #  The instruction uses value of the third operand\r\n        # CF_USE4 = 0x00800 #  The instruction uses value of the 4 operand\r\n        # CF_USE5 = 0x01000 #  The instruction uses value of the 5 operand\r\n        # CF_USE6 = 0x02000 #  The instruction uses value of the 6 operand\r\n        # CF_JUMP = 0x04000 #  The instruction passes execution using indirect jump or call (thus needs additional analysis)\r\n        # CF_SHFT = 0x08000 #  Bit-shift instruction (shl,shr...)\r\n        # CF_HLL  = 0x10000 #  Instruction may be present in a high level language function.\r\n        insn_feature = insn.get_canon_feature()\r\n        if insn_feature == 0:\r\n            return None\r\n\r\n        # Instruction mnemonic name\r\n        insn_mnem = insn.get_canon_mnem()\r\n\r\n        # BUGBUG: The IDA PowerPC processor module has a bug that causes 'b', 'blr', 'bctr', and 'bctrl' instructions to decode\r\n        # identically. Manually check the opcode bytes to determine for real what instruction this is.\r\n        insn_opcode = idc.Dword(ea)\r\n        if insn_opcode == 0x4E800020:\r\n            insn_mnem = \"blr\"\r\n        elif insn_opcode == 0x4E800420:\r\n            insn_mnem = \"bctr\"\r\n        elif insn_opcode == 0x4E800421:\r\n            insn_mnem = \"bctrl\"\r\n\r\n        #if insn_mnem in self.mnems: self.mnems[insn_mnem] += 1\r\n        #else:                       self.mnems[insn_mnem]  = 1\r\n\r\n        # Get instruction operand types\r\n        #\r\n        # op_t.type\r\n        #                    Description                          Data field\r\n        # o_void     =  0 #  No Operand                           ----------\r\n        # o_reg      =  1 #  General Register (al,ax,es,ds...)    reg\r\n        # o_mem      =  2 #  Direct Memory Reference  (DATA)      addr\r\n        # o_phrase   =  3 #  Memory Ref [Base Reg + Index Reg]    phrase\r\n        # o_displ    =  4 #  Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr\r\n        # o_imm      =  5 #  Immediate Value                      value\r\n        # o_far      =  6 #  Immediate Far Address  (CODE)        addr\r\n        # o_near     =  7 #  Immediate Near Address (CODE)        addr\r\n        insn_op1 = insn.Operands[0].type\r\n        insn_op2 = insn.Operands[1].type\r\n        insn_op3 = insn.Operands[2].type\r\n\r\n        ###############################################################\r\n        # Filter gadget\r\n        ###############################################################\r\n\r\n        # Filter gadgets with instructions that don't forward execution to the next address\r\n        if insn_feature & idaapi.CF_STOP:\r\n            if insn_mnem != \"blr\" and insn_mnem != \"bctrl\":\r\n                return None\r\n\r\n        # Filter gadgets with instructions in a bad list\r\n        elif insn_mnem in self.ropBadMnems:\r\n            return None\r\n\r\n        # Filter gadgets with branch instructions\r\n        # Note: conditional branches may still be useful if we can\r\n        #       set flags prior to calling them.\r\n        elif not self.ropAllowJcc and insn_mnem == \"b\":\r\n            return None\r\n\r\n        ###############################################################\r\n        # Get disassembly\r\n        ###############################################################\r\n        # NOTE: GENDSM_FORCE_CODE ensures correct decoding\r\n        #       of split instructions.\r\n        insn_disas = idc.GetDisasmEx(ea, idaapi.GENDSM_FORCE_CODE)\r\n        insn_disas = insn_disas.partition(';')[0]       # Remove comments from disassembly\r\n        insn_disas = ' '.join(insn_disas.split())       # Remove extraneous space from disassembly\r\n\r\n        ###############################################################\r\n        # Analyze instruction\r\n        ###############################################################\r\n\r\n        # Check for arithmetic operations\r\n        if insn_mnem in self.insn_arithmetic_ops:\r\n            insn_operations.add(\"math\")\r\n\r\n        # Check for bit-wise operations\r\n        if insn_mnem in self.insn_bit_ops:\r\n            insn_operations.add(\"bit\")\r\n\r\n        # Check if the operands are registers and record how it is used.\r\n        if insn_op1 == idaapi.o_reg:\r\n\r\n            reg1_name = self.get_o_reg_name(insn, 0)\r\n\r\n            # Check if the register is used or modified or both.\r\n            if insn_feature & idaapi.CF_USE1:\r\n                insn_use_registers.add(reg1_name)\r\n\r\n            if insn_feature & idaapi.CF_CHG1:\r\n                insn_chg_registers.add(reg1_name)\r\n\r\n            # Check for stack operation\r\n            if reg1_name == \"r1\":\r\n                insn_operations.add(\"stack\")\r\n\r\n                # Determine stack pivot distance\r\n                if insn_op3 == idaapi.o_imm:\r\n\r\n                    # NOTE: adb and sbb may also be useful, but let the user\r\n                    #       determine their use by locating the operations \"stack\"\r\n                    if insn_mnem == \"add\" or insn_mnem == \"addi\":\r\n                        insn_pivot += insn.Operands[2].value\r\n\r\n                    elif insn_mnem == \"sub\" or insn_mnem == \"subi\":\r\n                        insn_pivot -= insn.Operands[2].value\r\n\r\n            # Check for operations\r\n            if insn_op3 == idaapi.o_reg:\r\n                insn_operations.add(\"reg-to-reg\")\r\n            elif insn_op3 == idaapi.o_phrase or insn_op3 == idaapi.o_displ:\r\n                insn_operations.add(\"mem-to-reg\")\r\n\r\n        # Check second operand.\r\n        if insn_op2 == idaapi.o_reg or insn_op2 == idaapi.o_displ:\r\n\r\n            reg2_name = self.get_o_reg_name(insn, 1)\r\n            insn_use_registers.add(reg2_name)\r\n\r\n            # Check if the register is used or modified or both.\r\n            if insn_feature & idaapi.CF_CHG2:\r\n                insn_chg_registers.add(reg2_name)\r\n\r\n            # Check if the third operand is used and if not determine the instruction type.\r\n            if insn_feature & idaapi.CF_USE3 == 0:\r\n                # Two operand register\r\n                if insn_op2 == idaapi.o_reg:\r\n                    insn_operations.add(\"reg-to-reg\")\r\n\r\n                # Two operand immediate\r\n                elif insn_op2 == idaapi.o_imm:\r\n                    insn_operations.add(\"imm-reg\")\r\n\r\n                # Two operand reference\r\n                elif insn_op2 == idaapi.o_phrase or insn_op2 == idaapi.o_displ:\r\n                    # Hack to try and determine if the instruction is a load or store instruction.\r\n                    if insn_mnem[0] == \"l\":\r\n                        insn_operations.add(\"mem-reg\")\r\n                    else:\r\n                        insn_operations.add(\"reg-mem\")\r\n\r\n        # Check third operand.\r\n        if insn_op3 == idaapi.o_reg:\r\n\r\n            reg3_name = self.get_o_reg_name(insn, 2)\r\n\r\n            # Check if the register is used or modified or both.\r\n            if insn_feature & idaapi.CF_USE3:\r\n                insn_use_registers.add(reg3_name)\r\n\r\n            if insn_feature & idaapi.CF_CHG3:\r\n                insn_chg_registers.add(reg3_name)\r\n\r\n        # Build instruction dictionary\r\n        insn = dict()\r\n\r\n        insn[\"insn_mnem\"] = insn_mnem\r\n        insn[\"insn_disas\"] = insn_disas\r\n        insn[\"insn_operations\"] = insn_operations\r\n        insn[\"insn_chg_registers\"] = insn_chg_registers\r\n        insn[\"insn_use_registers\"] = insn_use_registers\r\n        insn[\"insn_pivot\"] = insn_pivot\r\n\r\n        return insn\r\n\r\n\r\n###############################################################################\r\n# Sploiter Engine\r\n\r\nclass ppc_Sploiter(Sploiter):\r\n    def __init__(self):\r\n\r\n        Sploiter.__init__(self)\r\n\r\n        # Initialize fields specific to this architecture.\r\n        self.bad_instructions = \"sc, rfid, twi\"\r\n\r\n        self.reg_list = [ \"r0\", \"r1\", \"r2\", \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\",\r\n                          \"r11\", \"r12\", \"r13\", \"r14\", \"r15\", \"r16\", \"r17\", \"r18\", \"r19\", \"r20\",\r\n                          \"r21\", \"r22\", \"r23\", \"r24\", \"r25\", \"r26\", \"r27\", \"r28\", \"r29\", \"r30\", \"r31\" ]\r\n\r\n    def is_func_ptr_supported(self):\r\n        return False\r\n\r\n    def get_func_ptr_instance(self):\r\n\r\n        # Currently not supported.\r\n        return None\r\n\r\n    def get_rop_instance(self):\r\n\r\n        return ppc_Rop(self)\r\n\t\t\r\n\r\nclass idasploiter_ppc_t(plugin_t):\r\n\r\n    flags = idaapi.PLUGIN_UNL\r\n    comment = \"\"\r\n    help = \"\"\r\n    wanted_name = \"\"\r\n    wanted_hotkey = \"\"\r\n\r\n    def init(self):\r\n        return idaapi.PLUGIN_SKIP\r\n\r\n    def run(self, arg):\r\n        pass\r\n\r\n    def term(self):\r\n        pass\r\n\r\ndef PLUGIN_ENTRY():\r\n    return idasploiter_ppc_t()"
  },
  {
    "path": "idasploiter_x86.py",
    "content": "#!/usr/bin/env python\r\n#\r\n# IDA Sploiter is an exploit development and vulnerability research environment\r\n# implemented as a plugin for Hex-Ray's IDA Pro disassembler.\r\n\r\n# Copyright (C) 2014 Peter Kacherginsky\r\n# All rights reserved.\r\n#\r\n# Redistribution and use in source and binary forms, with or without\r\n# modification, are permitted provided that the following conditions are met:\r\n#\r\n# 1. Redistributions of source code must retain the above copyright notice, this\r\n#    list of conditions and the following disclaimer.\r\n# 2. Redistributions in binary form must reproduce the above copyright notice,\r\n#    this list of conditions and the following disclaimer in the documentation\r\n#    and/or other materials provided with the distribution.\r\n# 3. Neither the name of the copyright holder nor the names of its contributors\r\n#    may be used to endorse or promote products derived from this software without\r\n#    specific prior written permission.\r\n#\r\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r\n# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n# Performance profiling\r\nimport cProfile\r\nimport pstats\r\n\r\n# IDA Sploiter\r\nfrom idasploiter import FuncPtr, Gadget, Ptr, Rop, read_module_memory, Sploiter\r\n\r\n# IDA libraries\r\nimport idaapi\r\nimport idautils\r\nimport idc\r\nfrom idaapi import Form, Choose2, plugin_t\r\n\r\n# Python libraries\r\nimport os\r\nimport binascii\r\nimport string\r\nimport textwrap\r\nimport copy\r\nimport csv\r\nimport itertools\r\nimport struct\r\n\r\nfrom struct import pack, unpack\r\nfrom ctypes import *\r\n\r\n\r\n###############################################################################\r\n# Function Pointer Search Engine\r\n\r\nclass x86_FuncPtr(FuncPtr):\r\n    def __init__(self, sploiter):\r\n\r\n        FuncPtr.__init__(self, sploiter)\r\n\r\n    # NOTE: Pointer Offsets are interpreted as follows:\r\n    # Example 1: Consider we have loaded fptr with a user controlled value\r\n    #\r\n    #              mov [fptr + offset], value\r\n    #\r\n    #            The fptr value we need is (fptr - offset) to overwrite\r\n    #            the actual fptr location. Do this early so that applied address\r\n    #            filters consider fptr bytes before offset adjustment.\r\n    #\r\n    #            Specify this positive offset in the Function Pointer form\r\n    #            so that it would be applied to all discovered function pointers.\r\n    #\r\n    # Example 2: Consider we have a pointer to a pointer write condition:\r\n    #\r\n    #              mov fptr, [p2p + offset2]\r\n    #              mov [fptr + offset1], value\r\n    #\r\n    #            The value (p2p - offset2) must point to the fptr location,\r\n    #            but since we have another offset the target of (p2p - offset2)\r\n    #            must be actually (fptr - offset1). Also do this early so that\r\n    #            applied address filters consider p2p before offset adjustment.\r\n    #\r\n    #            Specify this positive p2p offset2 so it gets applied to the listing\r\n    #            of pointers-to-pointers. All pointer-to-pointer(s) will also\r\n    #            be calculated relative to the ptr - offset1\r\n    #\r\n    # NOTE: Only search for pointers to pointers within the same module. This\r\n    #       was done purely for performance considerations since any readable\r\n    #       pointer to pointer may be used.\r\n\r\n\r\n    def search_pointers(self):\r\n\r\n        # HACK: A separate flag is used to track user canceling the search,\r\n        #       because multiple calls to idaapi.wasBreak() do not properly\r\n        #       detect cancellations.\r\n        breakFlag = False\r\n\r\n        # Show wait dialog\r\n        idaapi.show_wait_box(\"Searching writable function pointers...\")\r\n\r\n        for m in self.modules:\r\n\r\n            ###################################################################\r\n            # Locate all of the CALL and JMP instructions in the current module\r\n            # which use an immediate operand.\r\n\r\n            # List of call/jmp pointer calls in a given module\r\n            ptr_calls = list()\r\n\r\n            # Iterate over segments in the module\r\n            # BUG: Iterating over all loaded segments is more stable than looking up by address\r\n            for n in xrange(idaapi.get_segm_qty()):\r\n                seg = idaapi.getnseg(n)\r\n\r\n                # Segment in a selected modules\r\n                if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size):\r\n\r\n                    # Locate executable segments\r\n                    # NOTE: Each module may have multiple executable segments\r\n                    # TODO: Search for \"MOV REG, PTR # CALL REG\"\r\n                    if seg.perm & idaapi.SEGPERM_EXEC:\r\n\r\n                        # Search all instances of CALL /2 imm32/64 - FF 15\r\n                        # TODO: Alternative pointer calls using SIB: FF 14 E5 11 22 33 44 - call dword/qword ptr [0x44332211]\r\n                        #                                            FF 14 65 11 22 33 44\r\n                        #                                            FF 14 25 11 22 33 44\r\n                        call_ea = seg.startEA\r\n                        while True:\r\n                            call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, \"FF 15\", 16, idaapi.SEARCH_DOWN)\r\n                            if call_ea == idaapi.BADADDR: break\r\n                            ptr_calls.append(call_ea)\r\n\r\n                        # Search all instances of JMP /2 imm32/64 - FF 25\r\n                        # TODO: Alternative pointer calls using SIB: FF 24 E5 11 22 33 44 - jmp dword/qword ptr [0x44332211]\r\n                        #                                            FF 24 65 11 22 33 44\r\n                        #                                            FF 24 25 11 22 33 44\r\n                        call_ea = seg.startEA\r\n                        while True:\r\n                            call_ea = idaapi.find_binary(call_ea + 1, seg.endEA, \"FF 25\", 16, idaapi.SEARCH_DOWN)\r\n                            if call_ea == idaapi.BADADDR: break\r\n                            ptr_calls.append(call_ea)\r\n\r\n            ###################################################################\r\n            # Extract all of the function pointers and make sure they are\r\n            # are writable.\r\n\r\n            # List of writable function pointer objects in a given module\r\n            ptrs = list()\r\n\r\n            for call_ea in ptr_calls:\r\n\r\n                # Decode CALL/JMP instruction\r\n                # NOTE: May result in invalid disassembly of split instructions\r\n                insn_size = idaapi.decode_insn(call_ea)\r\n\r\n                if insn_size:\r\n\r\n                    insn = idaapi.cmd\r\n                    insn_op1 = insn.Operands[0].type\r\n\r\n                    # Verify first operand is a direct memory reference\r\n                    if insn.Operands[0].type == idaapi.o_mem:\r\n\r\n                        # Get operand address\r\n                        ptr_ea = insn.Operands[0].addr\r\n\r\n                        # Apply pointer offset\r\n                        ptr_ea -= self.ptrOffset\r\n\r\n                        # Locate segment where the pointer is located\r\n                        ptr_seg = idaapi.getseg(ptr_ea)\r\n\r\n                        # Make sure a valid segment writeable segment was found\r\n                        if ptr_seg and ptr_seg.perm & idaapi.SEGPERM_WRITE:\r\n\r\n                            # Get pointer charset\r\n                            ptr_charset = self.sploiter.get_ptr_charset(ptr_ea)\r\n\r\n                            # Filter the pointer\r\n                            if not self.filterP2P:\r\n                                if ptr_charset == None:                                    continue\r\n                                if self.ptrNonull and not \"nonull\" in ptr_charset: continue\r\n                                if self.ptrUnicode and not \"unicode\" in ptr_charset: continue\r\n                                if self.ptrAscii and not \"ascii\" in ptr_charset: continue\r\n                                if self.ptrAsciiPrint and not \"asciiprint\" in ptr_charset: continue\r\n                                if self.ptrAlphaNum and not \"alphanum\" in ptr_charset: continue\r\n                                if self.ptrNum and not \"numeric\" in ptr_charset: continue\r\n                                if self.ptrAlpha and not \"alpha\" in ptr_charset: continue\r\n\r\n                            # Increment the fptr counter\r\n\r\n                            # Get pointer disassembly\r\n                            insn_disas = idc.GetDisasmEx(call_ea, idaapi.GENDSM_FORCE_CODE)\r\n\r\n                            # Add pointer to the list\r\n                            ptr = Ptr(m.file, ptr_ea, self.ptrOffset, ptr_charset, call_ea, insn_disas)\r\n                            ptrs.append(ptr)\r\n\r\n            ###################################################################\r\n            # Cache Pointers to Pointers\r\n\r\n            ptr_ea_prefix_cache = dict()\r\n\r\n            if self.searchP2P:\r\n\r\n                # CACHE: Running repeated searches over the entire memory space is\r\n                #        very expensive. Let's cache all of the addresses containing\r\n                #        bytes corresponding to discovered function pointers in a\r\n                #        single search and simply reference this cache for each\r\n                #        function pointer. Specifically running idaapi.find_binary()\r\n                #        is much more expensive than idaapi.dbg_read_memory().\r\n                #\r\n                # NOTE:  For performance considerations, the cache works on a per\r\n                #        module basis, but could be expanded for the entire memory\r\n                #        space.\r\n                #\r\n                # prefix_offset - how many bytes of discovered function\r\n                #        pointers to cache.\r\n                #\r\n                #        Example: For function pointers 0x00401234, 0x00404321, 0x000405678\r\n                #        we are going to use prefix_offset 2, so we will cache all of the\r\n                #        values located at addresses 0x0040XXXX\r\n\r\n                if self.sploiter.addr64:\r\n                    pack_format = \"<Q\"\r\n                    addr_bytes = 8\r\n                    prefix_offset = 6\r\n                else:\r\n                    pack_format = \"<I\"\r\n                    addr_bytes = 4\r\n                    prefix_offset = 2\r\n\r\n                # Set of unique N-byte address prefixes to search in memory\r\n                ea_prefix_set = set()\r\n\r\n                for ptr in ptrs:\r\n                    ptr_ea = ptr.ptr_ea\r\n\r\n                    ptr_bytes = struct.pack(pack_format, ptr_ea)\r\n                    ptr_bytes = ptr_bytes[-prefix_offset:]\r\n\r\n                    ea_prefix_set.add(ptr_bytes)\r\n\r\n                # Search the module for all bytes corresponding to the prefix\r\n                # and use them as candidates for pointers-to-pointers\r\n\r\n                for ea_prefix in ea_prefix_set:\r\n\r\n                    # NOTE: Make sure you search using 44 33 22 11 format and not 11223344\r\n                    ea_prefix_str = \" \".join([\"%02x\" % ord(b) for b in ea_prefix])\r\n\r\n                    # Initialize search parameters for a given module\r\n                    ea = m.addr\r\n                    maxea = m.addr + m.size\r\n\r\n                    while True:\r\n                        ea = idaapi.find_binary(ea + 1, maxea, ea_prefix_str, 16, idaapi.SEARCH_DOWN)\r\n                        if ea == idaapi.BADADDR: break\r\n\r\n                        p2p_ea = ea - (addr_bytes - prefix_offset)\r\n\r\n                        dbg_mem = read_module_memory(p2p_ea, addr_bytes)\r\n                        ptr_ea_prefix = unpack(pack_format, dbg_mem)[0]\r\n\r\n                        if ptr_ea_prefix in ptr_ea_prefix_cache:\r\n                            ptr_ea_prefix_cache[ptr_ea_prefix].add(p2p_ea)\r\n                        else:\r\n                            ptr_ea_prefix_cache[ptr_ea_prefix] = set([p2p_ea, ])\r\n\r\n                        # Detect search cancellation, but allow the loop below\r\n                        # to run to create already cached/found function pointers\r\n\r\n                        # Canceled\r\n                        if breakFlag or idaapi.wasBreak():\r\n                            breakFlag = True\r\n                            break\r\n\r\n                    # Canceled\r\n                    if breakFlag or idaapi.wasBreak():\r\n                        breakFlag = True\r\n                        break\r\n\r\n            ###################################################################\r\n            # Locate Pointer to Pointers\r\n\r\n            for ptr in ptrs:\r\n\r\n                ptr_ea = ptr.ptr_ea\r\n\r\n                # Locate pointers-to-pointers for a given function pointer in the cache\r\n                if self.searchP2P and ptr_ea in ptr_ea_prefix_cache:\r\n\r\n                    for p2p_ea in ptr_ea_prefix_cache[ptr_ea]:\r\n\r\n                        # Apply pointer-to-pointer offset\r\n                        p2p_ea -= self.p2pOffset\r\n\r\n                        p2p_charset = self.sploiter.get_ptr_charset(p2p_ea)\r\n\r\n                        # Filter the pointer\r\n                        if self.filterP2P:\r\n                            if p2p_charset == None:                                    continue\r\n                            if self.ptrNonull and not \"nonull\" in p2p_charset: continue\r\n                            if self.ptrUnicode and not \"unicode\" in p2p_charset: continue\r\n                            if self.ptrAscii and not \"ascii\" in p2p_charset: continue\r\n                            if self.ptrAsciiPrint and not \"asciiprint\" in p2p_charset: continue\r\n                            if self.ptrAlphaNum and not \"alphanum\" in p2p_charset: continue\r\n                            if self.ptrNum and not \"numeric\" in p2p_charset: continue\r\n                            if self.ptrAlpha and not \"alpha\" in p2p_charset: continue\r\n\r\n                        # Copy existing pointer object to modify it for the particular p\r\n                        p2p = copy.copy(ptr)\r\n                        p2p.p2p_ea = p2p_ea\r\n                        p2p.p2p_offset = self.p2pOffset\r\n                        p2p.p2p_charset = p2p_charset\r\n\r\n                        # Apppend p2p specific pointer object to the global list\r\n                        self.ptrs.append(p2p)\r\n\r\n                        # Exceeded maximum number of pointers\r\n                        if self.maxPtrs and len(self.ptrs) >= self.maxPtrs:\r\n                            breakFlag = True\r\n                            print \"[idasploiter] Maximum number of pointers exceeded.\"\r\n                            break\r\n\r\n                # Simply append pointer object to the global list\r\n                else:\r\n                    self.ptrs.append(ptr)\r\n\r\n                    # Exceeded maximum number of pointers\r\n                    if self.maxPtrs and len(self.ptrs) >= self.maxPtrs:\r\n                        breakFlag = True\r\n                        print \"[idasploiter] Maximum number of pointers exceeded.\"\r\n                        break\r\n\r\n                if breakFlag or idaapi.wasBreak():\r\n                    breakFlag = True\r\n                    break\r\n\r\n            # Canceled\r\n            # NOTE: Only works when started from GUI not script.\r\n            if breakFlag or idaapi.wasBreak():\r\n                breakFlag = True\r\n                print \"[idasploiter] Canceled.\"\r\n                break\r\n\r\n        print \"[idasploiter] Found %d total pointers.\" % len(self.ptrs)\r\n        idaapi.hide_wait_box()\r\n\r\n\r\n###############################################################################\r\n# ROP Search Engine\r\n\r\nclass x86_Rop(Rop):\r\n    def __init__(self, sploiter):\r\n\r\n        Rop.__init__(self, sploiter)\r\n\r\n        # Extra bytes to read to ensure correct decoding of\r\n        # RETN, RETN imm16, CALL /2, and JMP /4 instructions.\r\n        self.dbg_read_extra = 6  # FF + ModR/M + SIB + disp32\r\n\r\n        self.insn_arithmetic_ops = [\"inc\", \"dec\", \"neg\", \"add\", \"sub\", \"mul\", \"imul\", \"div\", \"idiv\", \"adc\", \"sbb\",\r\n                                    \"lea\"]\r\n        self.insn_bit_ops = [\"not\", \"and\", \"or\", \"xor\", \"shr\", \"shl\", \"sar\", \"sal\", \"shld\", \"shrd\", \"ror\", \"rcr\", \"rcl\"]\r\n\r\n    def get_o_reg_name(self, insn, n):\r\n\r\n        reg_num = insn.Operands[n].reg\r\n        reg_name = self.regnames[reg_num]\r\n\r\n        # NOTE: IDA's x86/x86-64 regname array contains only register root names\r\n        #       (e.g ax,cx,dx,etc.). However we can still figure out exact register\r\n        #       size by looking at the operand 'dtyp' property.\r\n        if reg_num < 8:\r\n\r\n            # 32-bit register\r\n            if insn.Operands[n].dtyp == idaapi.dt_dword:\r\n                reg_name = 'e' + reg_name\r\n\r\n            # 64-bit register\r\n            elif insn.Operands[n].dtyp == idaapi.dt_qword:\r\n                reg_name = 'r' + reg_name\r\n\r\n                # 16-bit register otherwise\r\n\r\n        return reg_name\r\n\r\n    def search_retns(self):\r\n\r\n        if not self.debug: print(\"found %d modules\" % len(self.modules))\r\n        for m in self.modules:\r\n\r\n            # Iterate over segments in the module\r\n            # BUG: Iterating over all loaded segments is more stable than looking up by address\r\n            if not self.debug: print(\"found %d segments\" % idaapi.get_segm_qty())\r\n            for n in xrange(idaapi.get_segm_qty()):\r\n                seg = idaapi.getnseg(n)\r\n\r\n                # Locate executable segments in a selected modules\r\n                # NOTE: Each module may have multiple executable segments\r\n                if seg and seg.startEA >= m.addr and seg.endEA <= (m.addr + m.size):\r\n                    # If the debugger is attached then we can check if the segment is executable, else\r\n                    # just check if it is code or not.\r\n                    if idaapi.dbg_can_query() and idaapi.get_process_state() < 0:\r\n                        if seg.perm & idaapi.SEGPERM_EXEC == 0:\r\n                            continue\r\n                    elif seg.type & idaapi.SEG_CODE == 0:\r\n                        continue\r\n\r\n                    #######################################################\r\n                    # Search for ROP gadgets\r\n                    if self.searchRop:\r\n\r\n                        # Search all instances of RETN\r\n                        ea = seg.startEA\r\n                        while True:\r\n                            ea = idaapi.find_binary(ea + 1, seg.endEA, \"C3\", 16, idaapi.SEARCH_DOWN)\r\n                            if ea == idaapi.BADADDR: break\r\n                            self.retns.append((ea, m.file))\r\n\r\n                        # Search all instances of RETN imm16\r\n                        ea = seg.startEA\r\n                        while True:\r\n                            ea = idaapi.find_binary(ea + 1, seg.endEA, \"C2\", 16, idaapi.SEARCH_DOWN)\r\n                            if ea == idaapi.BADADDR: break\r\n\r\n                            # Read imm16 value and filter large values\r\n                            retn_imm16 = read_module_memory(ea + 1, 0x2)\r\n                            retn_imm16 = unpack(\"<H\", retn_imm16)[0]\r\n\r\n                            if retn_imm16 <= self.maxRetnImm:\r\n                                self.retns.append((ea, m.file))\r\n\r\n                    #######################################################\r\n                    # Search for JOP gadgets\r\n                    if self.searchJop:\r\n\r\n                        # Search all instances of JMP reg (FF /4) and CALL reg (FF /2)\r\n                        ea = seg.startEA\r\n                        while True:\r\n                            ea = idaapi.find_binary(ea + 1, seg.endEA, \"FF\", 16, idaapi.SEARCH_DOWN)\r\n                            if ea == idaapi.BADADDR: break\r\n\r\n                            # Read possible ModR/M, SIB, and IMM8/IMM32 bytes\r\n                            jop = read_module_memory(ea + 1, 0x6)\r\n                            if jop == None or len(jop) == 0:\r\n                                continue\r\n\r\n                            ###################################################\r\n                            # JMP/CALL reg\r\n                            if jop[0] in [\"\\xe0\", \"\\xe1\", \"\\xe2\", \"\\xe3\", \"\\xe4\", \"\\xe5\", \"\\xe6\", \"\\xe7\",\r\n                                          \"\\xd0\", \"\\xd1\", \"\\xd2\", \"\\xd3\", \"\\xd4\", \"\\xd5\", \"\\xd6\", \"\\xd7\"]:\r\n                                self.retns.append((ea, m.file))\r\n\r\n                            ###################################################\r\n                            # JMP/CALL [reg] no SIB\r\n                            # NOTE: Do not include pure [disp] instruction.\r\n\r\n                            # JMP/CALL [reg] no *SP,*BP\r\n                            elif jop[0] in [\"\\x20\", \"\\x21\", \"\\x22\", \"\\x23\", \"\\x26\", \"\\x27\",\r\n                                            \"\\x10\", \"\\x11\", \"\\x12\", \"\\x13\", \"\\x16\", \"\\x17\"]:\r\n                                self.retns.append((ea, m.file))\r\n\r\n                            # JMP/CALL [reg + imm8] no *SP\r\n                            elif jop[0] in [\"\\x60\", \"\\x61\", \"\\x62\", \"\\x63\", \"\\x65\", \"\\x66\", \"\\x67\",\r\n                                            \"\\x50\", \"\\x51\", \"\\x52\", \"\\x53\", \"\\x55\", \"\\x56\", \"\\x57\"]:\r\n                                jop_imm8 = jop[1]\r\n                                jop_imm8 = unpack(\"b\", jop_imm8)[0]  # signed\r\n\r\n                                if jop_imm8 <= self.maxJopImm:\r\n                                    self.retns.append((ea, m.file))\r\n\r\n\r\n                            # JMP/CALL [reg + imm32] no *SP\r\n                            elif jop[0] in [\"\\xa0\", \"\\xa1\", \"\\xa2\", \"\\xa3\", \"\\xa5\", \"\\xa6\", \"\\xa7\",\r\n                                            \"\\x90\", \"\\x91\", \"\\x92\", \"\\x93\", \"\\x95\", \"\\x96\", \"\\x97\"]:\r\n                                jop_imm32 = jop[1:5]\r\n                                jop_imm32 = unpack(\"<i\", jop_imm32)[0]  # signed\r\n\r\n                                if jop_imm32 <= self.maxJopImm:\r\n                                    self.retns.append((ea, m.file))\r\n\r\n                            ###################################################\r\n                            # JMP/CALL [reg] with SIB\r\n                            # NOTE: Do no include pure [disp] instructions in SIB ([*] - none)\r\n                            elif (jop[0] in [\"\\x24\", \"\\x64\", \"\\xa4\"] and not jop[1] in [\"\\x25\", \"\\x65\", \"\\xad\",\r\n                                                                                        \"\\xe5\"]) or \\\r\n                                    (jop[0] in [\"\\x14\", \"\\x54\", \"\\x94\"] and not jop[1] in [\"\\x25\", \"\\x65\", \"\\xad\",\r\n                                                                                           \"\\xe5\"]):\r\n\r\n                                # Check for displacement\r\n                                if jop[0] in [\"\\x64\", \"\\x54\"]:\r\n                                    jop_imm8 = jop[2]\r\n                                    jop_imm8 = unpack(\"b\", jop_imm8)[0]  # signed\r\n\r\n                                    if jop_imm8 <= self.maxJopImm:\r\n                                        self.retns.append((ea, m.file))\r\n\r\n                                elif jop[0] in [\"\\xa4\", \"\\x94\"]:\r\n                                    jop_imm32 = jop[2:6]\r\n                                    jop_imm32 = unpack(\"<i\", jop_imm32)[0]  # signed\r\n\r\n                                    if jop_imm32 <= self.maxJopImm:\r\n                                        self.retns.append((ea, m.file))\r\n\r\n                                else:\r\n                                    self.retns.append((ea, m.file))\r\n\r\n        print \"[idasploiter] Found %d returns\" % len(self.retns)\r\n\r\n    def search_gadgets(self):\r\n\r\n        count_total = len(self.retns)\r\n        count_notify = 0\r\n        count_curr = 0\r\n\r\n        # BUG: A separate flag is used to track user canceling the search,\r\n        #      because multiple calls to idaapi.wasBreak() do not properly\r\n        #      detect cancellations.\r\n        breakFlag = False\r\n\r\n        # Show wait dialog\r\n        if not self.debug: idaapi.show_wait_box(\"Searching gadgets: 00%%%%\")\r\n\r\n        for (ea_end, module) in self.retns:\r\n\r\n            # Flush the gadgets cache for each new retn pointer\r\n            self.gadgets_cache = dict()\r\n\r\n            # Flush memory cache for each new retn pointer\r\n            self.dbg_mem_cache = None\r\n\r\n            # CACHE: It is faster to read as much memory in one blob than to make incremental reads backwards.\r\n            #        Try to read and cache self.maxRopOffset bytes back. In cases where it is not possible,\r\n            #        then simply try to read the largest chunk.\r\n\r\n            # NOTE: Read a bit extra to cover correct decoding of RETN, RETN imm16, CALL /2, and JMP /4 instructions.\r\n\r\n            for i in range(self.maxRopOffset):\r\n                self.dbg_mem_cache = read_module_memory(ea_end - self.maxRopOffset + i,\r\n                                                        self.maxRopOffset - i + self.dbg_read_extra)\r\n                if self.dbg_mem_cache != None:\r\n                    break\r\n\r\n            # Check to make sure we have actual data to work with.\r\n            if self.dbg_mem_cache == None:\r\n                continue\r\n\r\n            # Search all possible gadgets up to maxoffset bytes back\r\n            # NOTE: Try all byte combinations to capture longer/more instructions\r\n            #       even with bad bytes in the middle.\r\n            for i in range(1, len(self.dbg_mem_cache) - self.dbg_read_extra):\r\n\r\n                ea = ea_end - i\r\n\r\n                # Get pointer charset\r\n                ptr_charset = self.sploiter.get_ptr_charset(ea)\r\n\r\n                # Filter the pointer\r\n                if ptr_charset == None:                                    continue\r\n                if self.ptrNonull and not \"nonull\" in ptr_charset: continue\r\n                if self.ptrUnicode and not \"unicode\" in ptr_charset: continue\r\n                if self.ptrAscii and not \"ascii\" in ptr_charset: continue\r\n                if self.ptrAsciiPrint and not \"asciiprint\" in ptr_charset: continue\r\n                if self.ptrAlphaNum and not \"alphanum\" in ptr_charset: continue\r\n                if self.ptrNum and not \"numeric\" in ptr_charset: continue\r\n                if self.ptrAlpha and not \"alpha\" in ptr_charset: continue\r\n\r\n                # Try to build a gadget at the pointer\r\n                gadget = self.build_gadget(ea, ea_end)\r\n\r\n                # Successfully built the gadget\r\n                if gadget:\r\n\r\n                    # Populate gadget object with more data\r\n                    gadget.address = ea\r\n                    gadget.module = module\r\n                    gadget.ptr_charset = ptr_charset\r\n\r\n                    # Filter gadgets with too many instruction\r\n                    if gadget.size > self.maxRopSize:\r\n                        break\r\n\r\n                    # Append newly built gadget\r\n                    self.gadgets.append(gadget)\r\n                    self.gadgets_cache[ea] = gadget\r\n\r\n                    # Exceeded maximum number of gadgets\r\n                    if self.maxRops and len(self.gadgets) >= self.maxRops:\r\n                        breakFlag = True\r\n                        print \"[idasploiter] Maximum number of gadgets exceeded.\"\r\n                        break\r\n                else:\r\n                    self.gadgets_cache[ea] = None\r\n\r\n                if breakFlag or idaapi.wasBreak():\r\n                    breakFlag = True\r\n                    break\r\n\r\n            # Canceled\r\n            # NOTE: Only works when started from GUI not script.\r\n            if breakFlag or idaapi.wasBreak():\r\n                breakFlag = True\r\n                print \"[idasploiter] Canceled.\"\r\n                break\r\n\r\n            # Progress report\r\n            if not self.debug and count_curr >= count_notify:\r\n                # NOTE: Need to use %%%% to escape both Python and IDA's format strings\r\n                idaapi.replace_wait_box(\"Searching gadgets: %02d%%%%\" % (count_curr * 100 / count_total))\r\n\r\n                count_notify += 0.10 * count_total\r\n\r\n            count_curr += 1\r\n\r\n        print \"[idasploiter] Found %d gadgets.\" % len(self.gadgets)\r\n        if not self.debug: idaapi.hide_wait_box()\r\n\r\n    # Attempt to build a gadget at the provided start address\r\n    # by verifying it properly terminates at the expected RETN.\r\n    def build_gadget(self, ea, ea_end):\r\n\r\n        instructions = list()\r\n        chg_registers = set()\r\n        use_registers = set()\r\n        operations = set()\r\n        pivot = 0\r\n\r\n        # Process each instruction in the gadget\r\n        while ea <= ea_end:\r\n\r\n            ###################################################################\r\n            # Gadget Level Cache:\r\n            #\r\n            # Locate a gadget (failed or built) starting at this address.\r\n            # If one is located, then we don't need to process any further\r\n            # instructions and just get necessary data from the cached\r\n            # gadget to never have to process the same address twice.\r\n            if ea in self.gadgets_cache:\r\n\r\n                # Check if the gadget was build successfully\r\n                gadget_cache = self.gadgets_cache[ea]\r\n\r\n                # Build the reset of the gadget from cache\r\n                if gadget_cache:\r\n\r\n                    for insn in gadget_cache.instructions:\r\n                        instructions.append(insn)\r\n\r\n                    for reg in gadget_cache.chg_registers:\r\n                        chg_registers.add(reg)\r\n\r\n                    for reg in gadget_cache.use_registers:\r\n                        use_registers.add(reg)\r\n\r\n                    for op in gadget_cache.operations:\r\n                        operations.add(op)\r\n\r\n                    pivot += gadget_cache.pivot\r\n\r\n                    gadget = Gadget(instructions, pivot, operations, chg_registers, use_registers)\r\n                    return gadget\r\n\r\n                # Previous attempt to build gadget at this address failed\r\n                else:\r\n                    return None\r\n\r\n            # Process new instruction\r\n            else:\r\n\r\n                # Instruction length\r\n                # NOTE: decode_insn also sets global idaapi.cmd\r\n                #       which contains insn_t structure\r\n                insn_size = idaapi.decode_insn(ea)\r\n\r\n                # Check successful decoding of the instruction\r\n                if insn_size:\r\n\r\n                    # Decoded instruction is too big to be a RETN or RETN imm16\r\n                    if ea + insn_size > ea_end + self.dbg_read_extra:\r\n                        return None\r\n\r\n                    ###############################################################\r\n                    # Instruction Level Cache\r\n                    #\r\n                    # Most instructions are repetitive so we can just cache\r\n                    # unique byte combinations to avoid costly decoding more\r\n                    # than once\r\n\r\n                    # Read instruction from memory cache\r\n                    dbg_mem_offset = ea - (ea_end - (len(self.dbg_mem_cache) - self.dbg_read_extra))\r\n                    dbg_mem = self.dbg_mem_cache[dbg_mem_offset:dbg_mem_offset + insn_size]\r\n\r\n                    # Create instruction cache if it doesn't already exist\r\n                    if not dbg_mem in self.insn_cache:\r\n                        ###########################################################\r\n                        # Decode instruction\r\n                        ###########################################################\r\n\r\n                        # Get global insn_t structure describing the instruction\r\n                        # NOTE: copy() is expensive, so we keep this single-threaded\r\n                        insn = idaapi.cmd\r\n\r\n                        #######################################################\r\n                        # Decode and Cache instruction characteristics\r\n                        self.insn_cache[dbg_mem] = self.decode_instruction(insn, ea, ea_end)\r\n\r\n                    ##################################################################\r\n                    # Retrieve cached instruction and apply it to the gadget\r\n\r\n                    # Check that cached instruction contains valid data\r\n                    if self.insn_cache[dbg_mem]:\r\n\r\n                        # Retrieve basic instruction characteristics\r\n                        insn_mnem = self.insn_cache[dbg_mem][\"insn_mnem\"]\r\n                        insn_disas = self.insn_cache[dbg_mem][\"insn_disas\"]\r\n                        instructions.append(insn_disas)\r\n\r\n                        #######################################################\r\n                        # Expected ending instruction of the gadget\r\n                        if ea == ea_end:\r\n                            gadget = Gadget(instructions, pivot, operations, chg_registers, use_registers)\r\n                            return gadget\r\n\r\n                        #######################################################\r\n                        # Filter out of place ROP/JOP/COP terminators\r\n                        # NOTE: retn/jmp/call are allowed, but only in the last position\r\n\r\n                        # Unexpected return instruction\r\n                        elif insn_mnem == \"retn\":\r\n                            return None\r\n\r\n                        # Unexpected call/jmp instruction\r\n                        elif insn_mnem in [\"jmp\", \"call\"]:\r\n                            return None\r\n\r\n                        #######################################################\r\n                        # Add instruction instruction characteristics to the gadget\r\n                        else:\r\n\r\n                            for reg in self.insn_cache[dbg_mem][\"insn_chg_registers\"]:\r\n                                chg_registers.add(reg)\r\n\r\n                            for reg in self.insn_cache[dbg_mem][\"insn_use_registers\"]:\r\n                                use_registers.add(reg)\r\n\r\n                            for op in self.insn_cache[dbg_mem][\"insn_operations\"]:\r\n                                operations.add(op)\r\n\r\n                            pivot += self.insn_cache[dbg_mem][\"insn_pivot\"]\r\n\r\n                    # Previous attempt to decode the instruction invalidated the gadget\r\n                    else:\r\n                        return None\r\n\r\n                    ###############################################################\r\n                    # Next instruction\r\n                    # NOTE: This is outside cache\r\n                    ea += insn_size\r\n\r\n                ###################################################################\r\n                # Failed decoding of the instruction\r\n                # NOTE: Gadgets may have bad instructions in the middle which\r\n                #       can be tolerated as long as we can find a useful instruction\r\n                #       further out.\r\n                else:\r\n\r\n                    # HACK: IDA does not disassemble \"\\x00\\x00\" unless you enable\r\n                    #       \"Disassemble zero opcode instructions\" in Processor Options.\r\n                    #       Since this option is normally disabled, I will attempt\r\n                    #       to get this instruction manually.\r\n\r\n                    # Read two bytes from memory cache at current instruction candidate\r\n                    dbg_mem_offset = ea - (ea_end - self.maxRopOffset)\r\n                    dbg_mem = self.dbg_mem_cache[dbg_mem_offset:dbg_mem_offset + 2]\r\n\r\n                    # BUGFIX: For some reason the length of dbg_mem may be 0 (perhaps we ran out of cache?), so\r\n                    # verify the size is valid before using the buffer.\r\n                    if len(dbg_mem) != 2:\r\n                        return None\r\n\r\n                    # Compare to two zero bytes\r\n                    if dbg_mem[:2] == \"\\x00\\x00\":\r\n\r\n                        if self.sploiter.addr64:\r\n                            instructions.append(\"add [rax],al\")\r\n                        else:\r\n                            instructions.append(\"add [eax],al\")\r\n\r\n                        use_registers.add(\"al\")\r\n                        operations.add(\"reg-to-mem\")\r\n\r\n                        ea += 2\r\n\r\n                    # \"MOV Sreg, r/m16\" instructions will result in illegal instruction exception: c000001d\r\n                    # or the memory couldn't be read exception: c0000005 which we don't want in our gadgets.\r\n                    elif dbg_mem[0] == \"\\x8E\":\r\n                        return None\r\n\r\n                    # Record a \"bad byte\" if allowed\r\n                    elif dbg_mem and not self.ropNoBadBytes:\r\n                        byte = dbg_mem[0]\r\n\r\n                        instructions.append(\"db %sh\" % binascii.hexlify(byte))\r\n\r\n                        ea += 1\r\n\r\n                    # Invalidate the gadget\r\n                    else:\r\n                        return None\r\n\r\n        # Failed to build a gadget, because RETN instruction was not found\r\n        else:\r\n            return None\r\n\r\n    ###############################################################\r\n    # Decode instruction\r\n\r\n    def decode_instruction(self, insn, ea, ea_end):\r\n\r\n        # Instruction specific characteristics\r\n        insn_chg_registers = set()\r\n        insn_use_registers = set()\r\n        insn_operations = set()\r\n        insn_pivot = 0\r\n\r\n        # Instruction feature\r\n        #\r\n        # instruc_t.feature\r\n        #\r\n        # CF_STOP = 0x00001 #  Instruction doesn't pass execution to the next instruction\r\n        # CF_CALL = 0x00002 #  CALL instruction (should make a procedure here)\r\n        # CF_CHG1 = 0x00004 #  The instruction modifies the first operand\r\n        # CF_CHG2 = 0x00008 #  The instruction modifies the second operand\r\n        # CF_CHG3 = 0x00010 #  The instruction modifies the third operand\r\n        # CF_CHG4 = 0x00020 #  The instruction modifies 4 operand\r\n        # CF_CHG5 = 0x00040 #  The instruction modifies 5 operand\r\n        # CF_CHG6 = 0x00080 #  The instruction modifies 6 operand\r\n        # CF_USE1 = 0x00100 #  The instruction uses value of the first operand\r\n        # CF_USE2 = 0x00200 #  The instruction uses value of the second operand\r\n        # CF_USE3 = 0x00400 #  The instruction uses value of the third operand\r\n        # CF_USE4 = 0x00800 #  The instruction uses value of the 4 operand\r\n        # CF_USE5 = 0x01000 #  The instruction uses value of the 5 operand\r\n        # CF_USE6 = 0x02000 #  The instruction uses value of the 6 operand\r\n        # CF_JUMP = 0x04000 #  The instruction passes execution using indirect jump or call (thus needs additional analysis)\r\n        # CF_SHFT = 0x08000 #  Bit-shift instruction (shl,shr...)\r\n        # CF_HLL  = 0x10000 #  Instruction may be present in a high level language function.\r\n        insn_feature = insn.get_canon_feature()\r\n\r\n        # Instruction mnemonic name\r\n        insn_mnem = insn.get_canon_mnem()\r\n\r\n        # if insn_mnem in self.mnems: self.mnems[insn_mnem] += 1\r\n        # else:                       self.mnems[insn_mnem]  = 1\r\n\r\n        # Get instruction operand types\r\n        #\r\n        # op_t.type\r\n        #                    Description                          Data field\r\n        # o_void     =  0 #  No Operand                           ----------\r\n        # o_reg      =  1 #  General Register (al,ax,es,ds...)    reg\r\n        # o_mem      =  2 #  Direct Memory Reference  (DATA)      addr\r\n        # o_phrase   =  3 #  Memory Ref [Base Reg + Index Reg]    phrase\r\n        # o_displ    =  4 #  Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr\r\n        # o_imm      =  5 #  Immediate Value                      value\r\n        # o_far      =  6 #  Immediate Far Address  (CODE)        addr\r\n        # o_near     =  7 #  Immediate Near Address (CODE)        addr\r\n        insn_op1 = insn.Operands[0].type\r\n        insn_op2 = insn.Operands[1].type\r\n\r\n        ###############################################################\r\n        # Filter gadget\r\n        ###############################################################\r\n\r\n        # Do not filter ROP, JOP, COP, always decode them\r\n        # NOTE: A separate check must be done to check if they are out of place.\r\n        if not insn_mnem in [\"retn\", \"jmp\", \"call\"]:\r\n\r\n            # Filter gadgets with instructions that don't forward execution to the next address\r\n            if insn_feature & idaapi.CF_STOP:\r\n                return None\r\n\r\n            # Filter gadgets with instructions in a bad list\r\n            elif insn_mnem in self.ropBadMnems:\r\n                return None\r\n\r\n            # Filter gadgets with jump instructions\r\n            # Note: conditional jumps may still be useful if we can\r\n            #       set flags prior to calling them.\r\n            elif not self.ropAllowJcc and insn_mnem[0] == \"j\":\r\n                return None\r\n\r\n        ###############################################################\r\n        # Get disassembly\r\n        ###############################################################\r\n        # NOTE: GENDSM_FORCE_CODE ensures correct decoding\r\n        #       of split instructions.\r\n        insn_disas = idc.GetDisasmEx(ea, idaapi.GENDSM_FORCE_CODE)\r\n        insn_disas = insn_disas.partition(';')[0]  # Remove comments from disassembly\r\n        insn_disas = ' '.join(insn_disas.split())  # Remove extraneous space from disassembly\r\n\r\n        ###############################################################\r\n        # Analyze instruction\r\n        ###############################################################\r\n\r\n        # Standalone instruction\r\n        if insn_op1 == idaapi.o_void:\r\n\r\n            # TODO: Determine and test how these instructions affect the stack\r\n            #       in 32-bit and 64-bit modes.\r\n            if insn_mnem in [\"pusha\", \"pushad\", \"popa\", \"popad\", \"pushf\", \"pushfd\", \"pushfq\", \"popf\", \"popfd\", \"popfq\"]:\r\n                insn_operations.add(\"stack\")\r\n\r\n                if insn_mnem in [\"popa\", \"popad\"]:\r\n                    insn_pivot += 7 * 4\r\n                elif insn_mnem in [\"pusha\", \"pushad\"]:\r\n                    insn_pivot -= 8 * 4\r\n                elif insn_mnem in [\"popf\", \"popfd\"]:\r\n                    insn_pivot += 4\r\n                elif insn_mnem in [\"pushf\", \"pushfd\"]:\r\n                    insn_pivot -= 4\r\n                elif insn_mnem == \"popfq\":  # TODO: Needs testing\r\n                    insn_pivot += 8\r\n                elif insn_mnem == \"pushfq\":  # TODO: Needs testing\r\n                    insn_pivot -= 8\r\n\r\n        # Single operand instruction\r\n        elif insn_op2 == idaapi.o_void:\r\n\r\n            # Single operand register\r\n            if insn_op1 == idaapi.o_reg:\r\n                insn_operations.add(\"one-reg\")\r\n\r\n                if insn_feature & idaapi.CF_CHG1:\r\n                    reg_name = self.get_o_reg_name(insn, 0)\r\n                    insn_chg_registers.add(reg_name)\r\n\r\n                    # Check for stack operation\r\n                    if reg_name[1:] == \"sp\":\r\n                        insn_operations.add(\"stack\")\r\n\r\n                        if insn_mnem == \"inc\":\r\n                            insn_pivot += 1\r\n\r\n                        elif insn_mnem == \"dec\":\r\n                            insn_pivot -= 1\r\n\r\n                elif insn_feature & idaapi.CF_USE1:\r\n                    reg_name = self.get_o_reg_name(insn, 0)\r\n                    insn_use_registers.add(reg_name)\r\n\r\n            # Single operand immediate\r\n            elif insn_op1 == idaapi.o_imm:\r\n                insn_operations.add(\"one-imm\")\r\n\r\n            # Single operand reference\r\n            # TODO: determine the [reg + ...] value if present\r\n            elif insn_op1 == idaapi.o_phrase or insn_op1 == idaapi.o_displ:\r\n                insn_operations.add(\"one-mem\")\r\n\r\n            # PUSH/POP mnemonic with a any operand type\r\n            if insn_mnem in [\"push\", \"pop\"]:\r\n                insn_operations.add(\"stack\")\r\n\r\n                # Adjust pivot based on operand size (32bit vs 64bit)\r\n                if insn_mnem == \"pop\":\r\n                    if insn.Operands[0].dtyp == idaapi.dt_dword:\r\n                        insn_pivot += 4\r\n                    elif insn.Operands[0].dtyp == idaapi.dt_qword:\r\n                        insn_pivot += 8\r\n                elif insn_mnem == \"push\":\r\n                    if insn.Operands[0].dtyp == idaapi.dt_dword:\r\n                        insn_pivot -= 4\r\n                    elif insn.Operands[0].dtyp == idaapi.dt_qword:\r\n                        insn_pivot -= 8\r\n\r\n            # Check for arithmetic operation:\r\n            if insn_mnem in self.insn_arithmetic_ops:\r\n                insn_operations.add(\"math\")\r\n\r\n            # Check for bit-wise operations:\r\n            if insn_mnem in self.insn_bit_ops:\r\n                insn_operations.add(\"bit\")\r\n\r\n        # Two operand instruction\r\n        else:\r\n\r\n            # Check for arithmetic operations\r\n            if insn_mnem in self.insn_arithmetic_ops:\r\n                insn_operations.add(\"math\")\r\n\r\n            # Check for bit-wise operations\r\n            if insn_mnem in self.insn_bit_ops:\r\n                insn_operations.add(\"bit\")\r\n\r\n            # Two operand instruction with the first operand a register\r\n            if insn_op1 == idaapi.o_reg:\r\n\r\n                reg_name = self.get_o_reg_name(insn, 0)\r\n\r\n                if insn_feature & idaapi.CF_CHG1:\r\n                    insn_chg_registers.add(reg_name)\r\n\r\n                    # Check for stack operation\r\n                    if reg_name[1:] == \"sp\":\r\n                        insn_operations.add(\"stack\")\r\n\r\n                        # Determine stack pivot distance\r\n                        if insn_op2 == idaapi.o_imm:\r\n\r\n                            # NOTE: adb and sbb may also be useful, but let the user\r\n                            #       determine their use by locating the operations \"stack\"\r\n                            if insn_mnem == \"add\":\r\n                                insn_pivot += insn.Operands[1].value\r\n\r\n                            elif insn_mnem == \"sub\":\r\n                                insn_pivot -= insn.Operands[1].value\r\n\r\n                    # Check for operations\r\n                    if insn_op2 == idaapi.o_reg:\r\n                        insn_operations.add(\"reg-to-reg\")\r\n                    elif insn_op2 == idaapi.o_imm:\r\n                        insn_operations.add(\"imm-to-reg\")\r\n\r\n                    # TODO: determine the [reg + ...] value if present\r\n                    elif insn_op2 == idaapi.o_phrase or insn_op2 == idaapi.o_displ:\r\n                        insn_operations.add(\"mem-to-reg\")\r\n\r\n                if insn_feature & idaapi.CF_USE1:\r\n                    insn_use_registers.add(reg_name)\r\n\r\n            # Two operand instruction with the second operand a register\r\n            if insn_op2 == idaapi.o_reg:\r\n\r\n                reg_name = self.get_o_reg_name(insn, 1)\r\n\r\n                if insn_feature & idaapi.CF_CHG2:\r\n                    insn_chg_registers.add(reg_name)\r\n\r\n                    # Check for stack operation\r\n                    if reg_name[1:] == \"sp\":\r\n                        insn_operations.add(\"stack\")\r\n\r\n                if insn_feature & idaapi.CF_USE2:\r\n                    insn_use_registers.add(reg_name)\r\n\r\n                # Check for operations\r\n                # TODO: determine the [reg + ...] value if present\r\n                if insn_op1 == idaapi.o_phrase or insn_op1 == idaapi.o_displ:\r\n                    insn_operations.add(\"reg-to-mem\")\r\n\r\n        # Build instruction dictionary\r\n        insn = dict()\r\n        insn[\"insn_mnem\"] = insn_mnem\r\n        insn[\"insn_disas\"] = insn_disas\r\n        insn[\"insn_operations\"] = insn_operations\r\n        insn[\"insn_chg_registers\"] = insn_chg_registers\r\n        insn[\"insn_use_registers\"] = insn_use_registers\r\n        insn[\"insn_pivot\"] = insn_pivot\r\n\r\n        return insn\r\n\r\n\r\n###############################################################################\r\n# Sploiter Engine\r\n\r\nclass x86_Sploiter(Sploiter):\r\n    def __init__(self):\r\n\r\n        Sploiter.__init__(self)\r\n\r\n        # Initialize fields specific to this architecture.\r\n        self.bad_instructions = \"leave, int, into, enter, syscall, sysenter, sysexit, sysret, in, out, loop, loope, loopne, lock, rep, repe, repz, repne, repnz\"\r\n\r\n        # Select general purpose registers for a given architecture\r\n        if self.addr64:\r\n            self.reg_list = [\"RAX\", \"RBX\", \"RCX\", \"RDX\", \"RSP\", \"RBP\", \"RSI\", \"RDI\", \"RIP\", \"R8\", \"R9\", \"R10\", \"R11\",\r\n                             \"R12\", \"R13\", \"R14\", \"R15\"]\r\n        else:\r\n            self.reg_list = [\"EAX\", \"EBX\", \"ECX\", \"EDX\", \"ESP\", \"EBP\", \"ESI\", \"EDI\", \"EIP\"]\r\n\r\n    def is_func_ptr_supported(self):\r\n        return True\r\n\r\n    def get_func_ptr_instance(self):\r\n\r\n        # Check processor type and create the function pointer class.\r\n        if idaapi.ph.id == idaapi.PLFM_386:\r\n            return x86_FuncPtr(self)\r\n        else:\r\n            return None\r\n\r\n    def get_rop_instance(self):\r\n\r\n        # Check the processor type and create the rop class.\r\n        if idaapi.ph.id == idaapi.PLFM_386:\r\n            return x86_Rop(self)\r\n        else:\r\n            return None\r\n\r\n\r\nclass idasploiter_x86_t(plugin_t):\r\n\r\n    flags = idaapi.PLUGIN_UNL\r\n    comment = \"\"\r\n    help = \"\"\r\n    wanted_name = \"\"\r\n    wanted_hotkey = \"\"\r\n\r\n    def init(self):\r\n        return idaapi.PLUGIN_SKIP\r\n\r\n    def run(self, arg):\r\n        pass\r\n\r\n    def term(self):\r\n        pass\r\n\r\ndef PLUGIN_ENTRY():\r\n    return idasploiter_x86_t()"
  }
]