From c6bfb7dd499f2aa1d4fb4f39dc3f49cb8801fed2 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 31 Jan 2019 21:50:15 +0100 Subject: Improved loop detection. --- src/analysis/disass/loop.c | 10 +++- tests/analysis/disass/block.py | 61 +++++++++++++++++++++++- tests/analysis/disass/jinit_color_converter.bin | Bin 0 -> 456 bytes tests/format/flat.py | 9 ++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/analysis/disass/jinit_color_converter.bin diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c index c37c7f6..b001992 100644 --- a/src/analysis/disass/loop.c +++ b/src/analysis/disass/loop.c @@ -409,7 +409,15 @@ static void define_basic_blocks_loops(GBlockList *list, bblock_info_t *info) links = get_block_predecessors(block, info, &count); for (k = 0; k < count; k++) - if (should_be_natural_loop_link(iter->iloop_header, links[k].info->iloop_header)) + if (should_be_natural_loop_link(iter->iloop_header, links[k].info->iloop_header) + /** + * Il se peut qu'un bloc fasse référence à lui même ! + * + * Cf. tests/analysis/disass/jinit_color_converter.bin + * + * On évite ici une boucle sans fin en officialisant cette boucle. + */ + || links[k].info == iter->iloop_header) { g_basic_block_get_boundaries(G_BASIC_BLOCK(links[k].linked), NULL, &last); g_basic_block_get_boundaries(G_BASIC_BLOCK(block), &first, NULL); diff --git a/tests/analysis/disass/block.py b/tests/analysis/disass/block.py index f8e6fe9..9b9d529 100644 --- a/tests/analysis/disass/block.py +++ b/tests/analysis/disass/block.py @@ -7,9 +7,12 @@ from chrysacase import ChrysalideTestCase from pychrysalide.analysis.contents import FileContent -from pychrysalide.analysis import LoadedBinary +from pychrysalide.analysis import BinRoutine, LoadedBinary from pychrysalide.arch import ArchInstruction +from pychrysalide.arch import vmpa from pychrysalide.format.elf import ElfFormat +from pychrysalide.format import FlatFormat +from pychrysalide.glibext import BinPortion import os import sys @@ -184,3 +187,59 @@ class TestBasicBlocks(ChrysalideTestCase): loop_count += 1 self.assertEqual(loop_count, 3) + + + def testOtherLoops(self): + """Check situation with some binary codes old troubles.""" + + # Malwre e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac + # Fonction jinit_color_converter de lib/armeabi/libgame.so + + fullname = sys.modules[self.__class__.__module__].__file__ + filename = os.path.basename(fullname) + + baselen = len(fullname) - len(filename) + + cnt = FileContent(fullname[:baselen] + 'jinit_color_converter.bin') + self.assertIsNotNone(cnt) + + fmt = FlatFormat(cnt) + + fmt.set_machine('armv7') + + base = vmpa(0, 0x12a524) + + p = BinPortion(BinPortion.BPC_CODE, base, cnt.size) + p.rights = BinPortion.PAC_READ | BinPortion.PAC_EXEC + + fmt.register_user_portion(p) + + fmt.register_code_point(base.virt + 1, True) + + sym = BinRoutine() + sym.range = p.range + + fmt.add_symbol(sym) + + binary = LoadedBinary(fmt) + + status = binary.analyze_and_wait() + self.assertTrue(status) + + loop_count = 0 + + for blk in sym.basic_blocks: + for _, dt in blk.destinations: + if dt == ArchInstruction.ILT_LOOP: + loop_count += 1 + + self.assertEqual(loop_count, 3) + + loop_count = 0 + + for ins in binary.processor.instrs: + for _, dt in ins.destinations: + if dt == ArchInstruction.ILT_LOOP: + loop_count += 1 + + self.assertEqual(loop_count, 3) diff --git a/tests/analysis/disass/jinit_color_converter.bin b/tests/analysis/disass/jinit_color_converter.bin new file mode 100644 index 0000000..1eb2715 Binary files /dev/null and b/tests/analysis/disass/jinit_color_converter.bin differ diff --git a/tests/format/flat.py b/tests/format/flat.py index 4ab5aa2..6924e42 100644 --- a/tests/format/flat.py +++ b/tests/format/flat.py @@ -8,7 +8,9 @@ from chrysacase import ChrysalideTestCase from pychrysalide.analysis import LoadedBinary from pychrysalide.analysis.contents import MemoryContent +from pychrysalide.arch import vmpa from pychrysalide.format import FlatFormat +from pychrysalide.glibext import BinPortion class TestFlatFormat(ChrysalideTestCase): @@ -25,6 +27,13 @@ class TestFlatFormat(ChrysalideTestCase): fmt = FlatFormat(cnt) fmt.set_machine('armv7') + base = vmpa(0, 0) + + p = BinPortion(BinPortion.BPC_CODE, base, cnt.size) + p.rights = BinPortion.PAC_READ | BinPortion.PAC_EXEC + + fmt.register_user_portion(p) + binary = LoadedBinary(fmt) binary.analyze_and_wait() -- cgit v0.11.2-87-g4458