Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IDA 7.[2-3] kernel32.{idb.i64} and fix tests #87

Merged
merged 5 commits into from
Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion idb/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,10 +593,13 @@ def pcb_version(self):
if self.len_sbytes == 119:
pass
# 7.20 <= ver <= 7.50?
elif self.len_sbytes in (141, 172):
elif self.len_sbytes in (141, 142, 172, 173):
jump_size = 1 if self.wordsize == 4 else 2
jump_size2 = 0 if self.wordsize == 4 else 1

if self.len_sbytes in (142, 173):
self.vsAddField("unknown-1", v_int8())
Copy link
Owner

@williballenthin williballenthin Jul 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recommend using an underscore rather than a dash, because vstruct will try to create an instance property with this name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it just an index -1, because I don't want to resort the latter.


self.vsAddField("genflags", v_uint8()) # 0x0c
self.vsAddField("lflags", v_uint16(bigend=True))
self.vsAddField("database_change_count", v_uint8())
Expand Down
Binary file added tests/data/v7.2/x32/kernel32.idb
Binary file not shown.
Binary file added tests/data/v7.2/x64/kernel32.i64
Binary file not shown.
Binary file added tests/data/v7.3/x32/kernel32.idb
Binary file not shown.
Binary file added tests/data/v7.3/x64/kernel32.i64
Binary file not shown.
29 changes: 14 additions & 15 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import pytest

import idb
import six

if six.PY2:
from functools32 import lru_cache
else:
from functools import lru_cache

try:
import capstone
Expand Down Expand Up @@ -57,6 +63,7 @@ def elf_idb():
yield db


@lru_cache(maxsize=16)
def load_idb(path):
with open(path, "rb") as f:
return idb.from_buffer(f.read())
Expand All @@ -74,14 +81,6 @@ def if_exists(*spec):
return ("if_exists", spec)


COMMON_FIXTURES = {
(695, 32): load_idb(os.path.join(CD, "data", "v6.95", "x32", "kernel32.idb")),
(695, 64): load_idb(os.path.join(CD, "data", "v6.95", "x64", "kernel32.i64")),
(700, 32): load_idb(os.path.join(CD, "data", "v7.0b", "x32", "kernel32.idb")),
(700, 64): load_idb(os.path.join(CD, "data", "v7.0b", "x64", "kernel32.i64")),
}


@pytest.fixture
def runslow(request):
return request.config.getoption("--runslow")
Expand Down Expand Up @@ -110,6 +109,10 @@ def test_foo(kernel32_idb, version, bitness, expected):
(695, 64, None),
(700, 32, None),
(700, 64, None),
(720, 32, None),
(720, 64, None),
(730, 32, None),
(730, 64, None),
]

ids = []
Expand All @@ -124,6 +127,8 @@ def test_foo(kernel32_idb, version, bitness, expected):
500: "v5.0",
695: "v6.95",
700: "v7.0b",
720: "v7.2",
730: "v7.3",
}
sversion = version_map[version] if version in version_map else str(version)

Expand All @@ -148,13 +153,7 @@ def test_foo(kernel32_idb, version, bitness, expected):
else:
marks = None

if not skipped:
if (version, bitness) in COMMON_FIXTURES:
db = COMMON_FIXTURES[(version, bitness)]
else:
db = load_idb(path)
else:
db = None
db = load_idb(path) if not skipped else None

if marks:
params.append(pytest.param(db, version, bitness, expected, marks=marks))
Expand Down
29 changes: 18 additions & 11 deletions tests/test_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ def test_root(kernel32_idb, version, bitness, expected):
assert root.get_field_tag("version") == "A"
assert root.get_field_index("version") == -1

assert root.version_string in ("6.95", "7.00")
assert root.open_count == 1
vs = str(version / 100)
assert root.version_string == vs if len(vs) == 4 else vs + "0"
assert root.open_count in (1, 2)
assert root.md5 == "00bf1bf1b779ce1af41371426821e0c2"


Expand Down Expand Up @@ -168,7 +169,10 @@ def test_function(kernel32_idb, version, bitness, expected):
# .text:689016B8 8B EC mov ebp, esp
# .text:689016BA 81 EC 14 02 00 00 sub esp, 214h
sub_689016B5 = idb.analysis.Function(kernel32_idb, 0x689016B5)
assert sub_689016B5.get_name() == "sub_689016B5"
if version <= 700:
assert sub_689016B5.get_name() == "sub_689016B5"
else:
assert sub_689016B5.get_name() == "__BaseDllInitialize@12"

chunks = list(sub_689016B5.get_chunks())
assert chunks == [
Expand Down Expand Up @@ -198,11 +202,11 @@ def test_function(kernel32_idb, version, bitness, expected):
assert sig.calling_convention == "__stdcall"
assert sig.rtype == "BOOL"
assert len(sig.parameters) == 3
assert list(map(lambda p: p.type, sig.parameters)) == [
"HINSTANCE",
"DWORD",
"LPVOID",
]
assert (
list(map(lambda p: p.type, sig.parameters)) == ["HINSTANCE", "DWORD", "LPVOID",]
if version <= 700
else ["HINSTANCE", "#E", "LPVOID",]
)
assert list(map(lambda p: p.name, sig.parameters)) == [
"hinstDLL",
"fdwReason",
Expand Down Expand Up @@ -583,7 +587,10 @@ def test_entrypoints2(kernel32_idb, version, bitness, expected):
1473,
"NTDLL.TpWaitForWork",
)
assert entrypoints[-1] == ("DllEntryPoint", 0x68901696, None, None)
if version <= 700:
assert entrypoints[-1] == ("DllEntryPoint", 0x68901696, None, None)
else:
assert entrypoints[-1] == ("_BaseDllInitialize@12", 0x68901696, None, None)


@kern32_test()
Expand All @@ -594,7 +601,7 @@ def test_idainfo(kernel32_idb, version, bitness, expected):
assert idainfo.tag == "IDA"
elif version == 700:
assert idainfo.tag == "ida"
assert idainfo.version == version
assert idainfo.version == min(version, 700)
assert idainfo.procname == "metapc"

# Portable Executable (PE)
Expand Down Expand Up @@ -652,7 +659,7 @@ def test_idainfo720plus(kernel32_idb, version, bitness, expected):

assert idainfo.maxref == 16
assert idainfo.netdelta == 0
assert idainfo.xrefnum == 2
assert idainfo.xrefnum in (2, 0)
assert idainfo.xrefflag == 0xF
# Visual C++
assert idainfo.cc_id == 0x01
Expand Down
71 changes: 49 additions & 22 deletions tests/test_idaapi.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import os

import pytest
from fixtures import *

import idb


def pluck(prop, s):
"""
Expand Down Expand Up @@ -220,7 +215,11 @@ def test_data(kernel32_idb, version, bitness, expected):
@kern32_test()
def test_function_name(kernel32_idb, version, bitness, expected):
api = idb.IDAPython(kernel32_idb)
assert api.idc.GetFunctionName(0x68901695) == "DllEntryPoint"
assert (
api.idc.GetFunctionName(0x68901695) == "DllEntryPoint"
if version <= 700
else "_BaseDllInitialize@12"
)


@kern32_test()
Expand Down Expand Up @@ -535,8 +534,16 @@ def test_functions(kernel32_idb, version, bitness, expected):
def test_function_names(kernel32_idb, version, bitness, expected):
api = idb.IDAPython(kernel32_idb)

assert api.idc.GetFunctionName(0x68901695) == "DllEntryPoint"
assert api.idc.GetFunctionName(0x689016B5) == "sub_689016b5"
assert (
api.idc.GetFunctionName(0x68901695) == "DllEntryPoint"
if version <= 700
else "_BaseDllInitialize@12"
)
assert (
api.idc.GetFunctionName(0x689016B5) == "sub_689016b5"
if version <= 700
else "__BaseDllInitialize@12"
)

with pytest.raises(KeyError):
# this is issue #7.
Expand All @@ -558,17 +565,23 @@ def test_all_function_names(kernel32_idb, version, bitness, expected):
def test_comments(kernel32_idb, version, bitness, expected):
api = idb.IDAPython(kernel32_idb)

expected = (
"jumptable 6892FF97 default case"
if version <= 700
else "jumptable 6892FF97 default case, cases 3,5-7"
)

assert api.ida_bytes.get_cmt(0x6890103C, False) == "Flags"
assert api.ida_bytes.get_cmt(0x689023B4, True) == "jumptable 6892FF97 default case"
assert api.ida_bytes.get_cmt(0x689023B4, True) == expected

assert api.idc.Comment(0x6890103C) == "Flags"
assert api.idc.RptCmt(0x6890103C) == ""

assert api.idc.RptCmt(0x689023B4) == "jumptable 6892FF97 default case"
assert api.idc.RptCmt(0x689023B4) == expected
assert api.idc.Comment(0x689023B4) == ""

assert api.idc.GetCommentEx(0x6890103C, False) == "Flags"
assert api.idc.GetCommentEx(0x689023B4, True) == "jumptable 6892FF97 default case"
assert api.idc.GetCommentEx(0x689023B4, True) == expected


@pytest.mark.slow
Expand Down Expand Up @@ -602,10 +615,11 @@ def test_all_comments(kernel32_idb, version, bitness, expected):
def test_LocByName(kernel32_idb, version, bitness, expected):
api = idb.IDAPython(kernel32_idb)

assert api.idc.LocByName("CancelIo") == 0x6892E70A
assert api.idc.GetFunctionName(api.idc.LocByName("CancelIo")) == "CancelIo"
if version <= 700:
assert api.idc.LocByName("CancelIo") == 0x6892E70A
assert api.idc.GetFunctionName(api.idc.LocByName("CancelIo")) == "CancelIo"

assert api.idc.LocByName("__does not exist__") == -1
assert api.idc.LocByName("__does not exist__") == -1


@kern32_test()
Expand Down Expand Up @@ -820,7 +834,11 @@ def test_exports(kernel32_idb, version, bitness, expected):
)

assert api.ida_entry.get_entry_ordinal(1572) == 0x68901695
assert api.ida_entry.get_entry_name(0x68901695) == "DllEntryPoint"
assert (
api.ida_entry.get_entry_name(0x68901695) == "DllEntryPoint"
if version <= 700
else "_BaseDllInitialize@12"
)


@kern32_test()
Expand All @@ -829,14 +847,17 @@ def test_GetType(kernel32_idb, version, bitness, expected):
assert (
api.idc.GetType(0x68901695)
== "BOOL __stdcall DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)"
if version <= 700
else "BOOL __stdcall _BaseDllInitialize@12(HINSTANCE hinstDLL, #E fdwReason, LPVOID lpReserved)"
)

# valid function, but no type data associated...

# .text:6899AE01 ; Attributes: bp-based frame
# .text:6899AE01
# .text:6899AE01 sub_6899AE01 proc near
assert api.idc.GetType(0x6899AE01) is None
if version <= 700:
assert api.idc.GetType(0x6899AE01) is None


@kern32_test()
Expand All @@ -861,18 +882,24 @@ def test_multi_bitness():
def test_name(kernel32_idb, version, bitness, expected):
api = idb.IDAPython(kernel32_idb)
assert api.ida_bytes.has_name(api.ida_bytes.get_flags(0x689DB190)) == True
assert api.ida_name.get_name(0x689DB190) == "FinestResolution"
assert (
api.ida_name.get_name(0x689DB190) == "FinestResolution"
if version <= 700
else "_MinimumTime"
)


@kern32_test()
def test_names(kernel32_idb, version, bitness, expected):
api = idb.IDAPython(kernel32_idb)
if version == 700:
assert len(list(api.idautils.Names())) == 14247
elif version == 695:
if version == 695:
assert len(list(api.idautils.Names())) == 14252
else:
raise ValueError("unexpected version")
elif version == 700:
assert len(list(api.idautils.Names())) == 14247
elif version == 720:
assert len(list(api.idautils.Names())) == 16457
elif version == 730:
assert len(list(api.idautils.Names())) == 16455


def test_anterior_lines():
Expand Down
5 changes: 3 additions & 2 deletions tests/test_idb.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,9 @@ def test_find_exact_match_min(kernel32_idb, version, bitness, expected):

@kern32_test()
def test_find_exact_match_max(kernel32_idb, version, bitness, expected):
maxkey = h2b("4e776373737472")
assert kernel32_idb.id0.find(maxkey).key == maxkey
if version <= 700:
maxkey = h2b("4e776373737472")
assert kernel32_idb.id0.find(maxkey).key == maxkey


@kern32_test()
Expand Down