summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-02-11 00:52:04 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-02-11 00:52:04 (GMT)
commit7fc86b4051b91adbd0b99f41c19d866ae0760586 (patch)
tree856f2583e349acb1144e035289ef71c2da2967b5
parent5863af232b8fc57de210702afe659a7383bb8840 (diff)
Improved the loop detection.
-rw-r--r--src/analysis/disass/loop.c55
-rw-r--r--tests/analysis/disass/block.py53
-rw-r--r--tests/analysis/disass/sub_a1bc.binbin0 -> 416 bytes
3 files changed, 96 insertions, 12 deletions
diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c
index b001992..c35bab7 100644
--- a/src/analysis/disass/loop.c
+++ b/src/analysis/disass/loop.c
@@ -78,6 +78,9 @@ static void tag_loop_head(bblock_info_t *, bblock_info_t *);
static bblock_info_t *traverse_basic_blocks_dfs(bblock_info_t *, GBlockList *, bblock_info_t *, unsigned int);
/* Indique si une boucle doit être définie. */
+static bool _should_be_natural_loop_link(bblock_info_t *, bblock_info_t *);
+
+/* Indique si une boucle doit être définie. */
static bool should_be_natural_loop_link(bblock_info_t *, bblock_info_t *);
/* Définit les boucles entre un ensemble de blocs basiques. */
@@ -356,7 +359,7 @@ static bblock_info_t *traverse_basic_blocks_dfs(bblock_info_t *root, GBlockList
* *
******************************************************************************/
-static bool should_be_natural_loop_link(bblock_info_t *dest, bblock_info_t *header)
+static bool _should_be_natural_loop_link(bblock_info_t *dest, bblock_info_t *header)
{
bool result; /* Conclusion à retourner */
@@ -372,6 +375,33 @@ static bool should_be_natural_loop_link(bblock_info_t *dest, bblock_info_t *head
/******************************************************************************
* *
+* Paramètres : dest = informations du bloc de destination. *
+* header = informations de l'entête de boucle. *
+* *
+* Description : Indique si une boucle doit être définie. *
+* *
+* Retour : true si une boucle naturelle est bien présente. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool should_be_natural_loop_link(bblock_info_t *dest, bblock_info_t *header)
+{
+ bool result; /* Conclusion à retourner */
+
+ result = _should_be_natural_loop_link(dest, header);
+
+ if (!result && dest->iloop_header != NULL)
+ result = should_be_natural_loop_link(dest->iloop_header, header);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : list = liste de blocs de code à consulter. *
* info = informations complémentaires quant aux blocs. *
* *
@@ -445,7 +475,7 @@ static void define_basic_blocks_loops(GBlockList *list, bblock_info_t *info)
links = get_block_successors(block, info, &count);
for (k = 0; k < count; k++)
- if (should_be_natural_loop_link(links[k].info, iter->iloop_header)
+ if (_should_be_natural_loop_link(links[k].info, iter->iloop_header)
/**
* Il se peut qu'un bloc fasse référence à lui même !
*
@@ -504,16 +534,23 @@ void detect_loops_in_basic_blocks(GBlockList *list)
count = g_block_list_count_blocks(list);
- if (count > 1)
- {
- info = calloc(count, sizeof(bblock_info_t));
+ /**
+ * Un premier jet consistait à filtrer sur le nombre de blocs : s'il n'y
+ * en avait qu'un, il n'y avait à priori pas de raison de rechercher des
+ * boucles !
+ *
+ * Mais c'était sans compter une routine se résumant à une boucle infinie...
+ *
+ * C'est par exemple le cas avec la fonction operator new[] (_ZnajRKSt9nothrow_t)
+ * de l'échantillon b6990fc6913d839809c72d1d482cb2c295c4840fc6a1f40f38923464e958ffae.
+ */
- traverse_basic_blocks_dfs(&info[0], list, info, 1);
+ info = calloc(count, sizeof(bblock_info_t));
- define_basic_blocks_loops(list, info);
+ traverse_basic_blocks_dfs(&info[0], list, info, 1);
- free(info);
+ define_basic_blocks_loops(list, info);
- }
+ free(info);
}
diff --git a/tests/analysis/disass/block.py b/tests/analysis/disass/block.py
index 9b9d529..0907542 100644
--- a/tests/analysis/disass/block.py
+++ b/tests/analysis/disass/block.py
@@ -192,14 +192,14 @@ class TestBasicBlocks(ChrysalideTestCase):
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)
+ # Malware e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac
+ # Fonction jinit_color_converter de lib/armeabi/libgame.so
+
cnt = FileContent(fullname[:baselen] + 'jinit_color_converter.bin')
self.assertIsNotNone(cnt)
@@ -243,3 +243,50 @@ class TestBasicBlocks(ChrysalideTestCase):
loop_count += 1
self.assertEqual(loop_count, 3)
+
+ # Malware 6e4b64ede44bf4cfb36da04aacc9a22ba73e11be2deac339e275d3bde3b31311
+ # Fonction sub_a1bc de lib/armeabi-v7a/liblamelib.so
+
+ cnt = FileContent(fullname[:baselen] + 'sub_a1bc.bin')
+ self.assertIsNotNone(cnt)
+
+ fmt = FlatFormat(cnt)
+
+ fmt.set_machine('armv7')
+
+ base = vmpa(0, 0xa1bc)
+
+ 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, 8)
+
+ 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, 8)
diff --git a/tests/analysis/disass/sub_a1bc.bin b/tests/analysis/disass/sub_a1bc.bin
new file mode 100644
index 0000000..dc18852
--- /dev/null
+++ b/tests/analysis/disass/sub_a1bc.bin
Binary files differ