avast / avast/retdec

Option to not remove any linked functions

Open
#370 1 comment 0 reactions 0 assignees View on GitHub
C-bin2llvmir enhancement P-output
Dominant language
C++
Stars
8.6k
Forks
1k
PR merge metrics
No merged PRs in 30d

Description

Hello!

This is more of question than an issue, any help appreciated. I'm trying to implement some analysis (e.g. based on data flow) on top of the generated IR. I've done some testing with [Ransomware.Cryptowall](https://github.com/ytisf/theZoo/tree/master/malwares/Binaries/Ransomware.Cryptowall) and stumbled over something:

- According to retdec-fileinfo (confirmed by IDA) there are 183 imports
- Only ~30 external declarations show up in the IR (those that get called)

From fileinfo:
```
[...]
99 InitCommonControlsEx COMCTL32.dll 123 0x40a030 No
100 ImageList_ReplaceIcon COMCTL32.dll 111 0x40a034 No
101 ImageList_Remove COMCTL32.dll 109 0x40a038 No
102 CreateToolbarEx COMCTL32.dll 14 0x40a03c No
[...]
```

These functions, for example, show up in the json file but not in the IR or decompiled file.

Is there any way to keep all external linked functions in the IR (either for retdec-decompiler.sh or retdec-bin2llvmir)? I assume the missing ones are removed because they are not directly called.

Options I have tried but didn't have any effect on this:

- --backend-no-opts
- --keep-unreachable-funcs
- --backend-keep-library-funcs

Taking a closer look shows that the other functions are not directly called but their pointers are stored in global variables (from IDA, which does a good job here naming the source):

```
.text:004091D0 push ebp
.text:004091D1 mov ebp, esp
.text:004091D3 mov eax, ds:CreateToolbarEx
.text:004091D8 mov dword_37CEE9C, eax
.text:004091DD mov ecx, ds:ImageList_Remove
.text:004091E3 mov dword_37CEEA0, ecx
.text:004091E9 mov edx, ds:ImageList_ReplaceIcon
.text:004091EF mov dword_37CEEA4, edx
[...]
```

The retdec generated IR and code miss this reference:

```
define i32 @function_4091d0() local_unnamed_addr {
dec_label_pc_4091d0:
%ebp.global-to-local = alloca i32, align 4
%v0_4091d0 = load i32, i32* %ebp.global-to-local, align 4
%v0_4091d3 = load i32, i32* inttoptr (i32 4235324 to i32*), align 4
store i32 %v0_4091d3, i32* @global_var_37cee9c.35, align 4
%v0_4091dd = load i32, i32* inttoptr (i32 4235320 to i32*), align 8
store i32 %v0_4091dd, i32* @global_var_37ceea0.36, align 4
[...]
```

```
int32_t function_4091d0(void) {
// 0x4091d0
g6 = *(int32_t *)0x40a03c;
g7 = *(int32_t *)0x40a038;
g8 = *(int32_t *)0x40a034;
g9 = *(int32_t *)0x40a030;
[...]
```

If such an option doesn't exist, could you give me a hint where those linked functions get removed (is it a LLVM pass or is this coming from retdec?) so I can patch that/create a pull request? In the end I guess the proper solution is to only remove linked functions after also checking alias and data flow analysis.

Contributor guide

No contributing guide indexed for this repository

Research direction

Reproduce the Cryptowall case with retdec-fileinfo, retdec-decompiler.sh, and retdec-bin2llvmir, comparing imported functions with external declarations in the generated IR. Trace where uncalled linked functions and references through global function pointers are removed. Done means an option or analysis change preserves the relevant external declarations, with the observed case covered by a regression check.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers, reverse-engineering
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.