Skip to content

Instantly share code, notes, and snippets.

@williballenthin
Created March 28, 2018 03:58
Show Gist options
  • Save williballenthin/9bc18a0a8600caaf96e40e0623e97ce5 to your computer and use it in GitHub Desktop.
Save williballenthin/9bc18a0a8600caaf96e40e0623e97ce5 to your computer and use it in GitHub Desktop.
function signatures in vivisect
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# function signatures in vivisect\n",
"\n",
"Vivisect supports a function signature feature similar to IDA Pro's FLIRT technology. It's called \"vamp\". We can use this to automatically identify statically-linked library functions.\n",
"\n",
"Our example file here comes from FireEye's malware analysis crash course. There's a statically-linked implementation of `strlen` that is not recognized by vanilla FLOSS."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import vivisect\n",
"import viv_utils"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"here's the statically-linked `strlen` implementation:\n",
"\n",
"![strlen](https://i.imgur.com/qlz5AsB.png)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"vw = viv_utils.getWorkspace(\"./Materials/Debugging/Labs/encStrings/binaries/encStrings.exe\")\n",
"STRLEN_VA = 0x401B60\n",
"assert vw.getFunction(STRLEN_VA) == STRLEN_VA"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's use the vamp subsystem to create a signature that matches this function."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"import vivisect.vamp"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('\\x8bL$\\x04\\xf7\\xc1\\x03\\x00\\x00\\x00t\\x14\\x8a\\x01A\\x84\\xc0t@\\xf7\\xc1\\x03\\x00\\x00\\x00u\\xf1\\x05\\x00\\x00\\x00\\x00\\x8b\\x01\\xba\\xff\\xfe\\xfe~\\x03\\xd0\\x83\\xf0\\xff3\\xc2\\x83\\xc1\\x04\\xa9\\x00\\x01\\x01\\x81t\\xe8\\x8bA\\xfc\\x84\\xc0t2\\x84\\xe4t$\\xa9\\x00\\x00\\xff\\x00t\\x13\\xa9\\x00\\x00\\x00\\xfft\\x02\\xeb\\xcd\\x8dA\\xff\\x8bL$\\x04+\\xc1\\xc3\\x8dA\\xfe\\x8bL$\\x04+\\xc1\\xc3\\x8dA\\xfd\\x8bL$\\x04+\\xc1\\xc3\\x8dA\\xfc\\x8bL$\\x04+\\xc1\\xc3',\n",
" '\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff',\n",
" 'library._strlen')]\n"
]
}
],
"source": [
"# ref: https://github.com/vivisect/vivisect/blob/030bf45f9b2859ade0f371c1837131c172e1b7d5/vivisect/vamp/__init__.py\n",
"strlen_sig = vivisect.vamp.genSigAndMask(vw, STRLEN_VA)\n",
"sigs = [strlen_sig + ('library._strlen', )]\n",
"from pprint import pprint\n",
"pprint(sigs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, we have a 1-element list of 3-tuples: `(byte value, byte mask, function name)`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's build a utility that can match our list of signatures:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"# ref: https://github.com/vivisect/vivisect/blob/030bf45f9b2859ade0f371c1837131c172e1b7d5/vivisect/vamp/msvc/__init__.py#L31\n",
"import envi.bytesig as e_bytesig\n",
"class FlossVamp(e_bytesig.SignatureTree):\n",
" def __init__(self):\n",
" e_bytesig.SignatureTree.__init__(self)\n",
" for bytes, masks, fname in sigs:\n",
" #bytes = bytes.decode('hex')\n",
" #if masks != None:\n",
" # masks = masks.decode('hex')\n",
" self.addSignature(bytes, masks=masks, val=fname)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
"import vivisect.vamp.msvc as v_msvc\n",
"from vivisect.const import *\n",
"\n",
"fv = FlossVamp()\n",
"\n",
"def analyzeFunction(vw, funcva):\n",
" offset, bytes = vw.getByteDef(funcva)\n",
" sig = fv.getSignature(bytes, offset)\n",
" if sig == None:\n",
" return\n",
" fname = sig.split(\".\")[-1]\n",
" vw.makeName(funcva, fname, filelocal=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we apply the signature to the given function, and see that it renames the statically-linked function:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'sub_00401b60'"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# before:\n",
"vw.getName(STRLEN_VA)"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"analyzeFunction(vw, STRLEN_VA)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'encstrings._strlen'"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# after:\n",
"vw.getName(STRLEN_VA)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment