From c6bfb7dd499f2aa1d4fb4f39dc3f49cb8801fed2 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
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