Skip to content

Instantly share code, notes, and snippets.

@secdev02
Forked from smx-smx/XZ Backdoor Analysis
Created March 31, 2024 12:38
Show Gist options
  • Save secdev02/f115b97d4c0e6ce199b3822176709c3c to your computer and use it in GitHub Desktop.
Save secdev02/f115b97d4c0e6ce199b3822176709c3c to your computer and use it in GitHub Desktop.

Revisions

  1. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -305,4 +305,4 @@ Program received signal SIGINT, Interrupt.
    ```

    At this point, you can issue `detach` and attach with other debuggers if needed.
    Once attached, set relevant breakpoints and replace the original bytes ("\xF3\x0F\x1E\xFA")
    Once attached, set relevant breakpoints and restore the original bytes ("\xF3\x0F\x1E\xFA")
  2. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -302,4 +302,7 @@ Program received signal SIGINT, Interrupt.
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```
    ```

    At this point, you can issue `detach` and attach with other debuggers if needed.
    Once attached, set relevant breakpoints and replace the original bytes ("\xF3\x0F\x1E\xFA")
  3. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 0 additions and 22 deletions.
    22 changes: 0 additions & 22 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -302,26 +302,4 @@ Program received signal SIGINT, Interrupt.
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    (gdb) bt
    #0 0x00007f8cb3b067f0 in ?? () from /root/sshd/liblzma.so.5.6.1
    #1 0x00007f8cb3b08c29 in lzma_crc32 () from /root/sshd/liblzma.so.5.6.1
    #2 0x00007f8cb3b4ffab in elf_machine_rela (skip_ifunc=<optimized out>,
    reloc_addr_arg=0x7f8cb3b3dda0 <lzma_crc32@got[plt]>, version=<optimized out>, sym=0x7f8cb3b03018,
    reloc=0x7f8cb3b04fc8, scope=0x7f8cb3b3f4f8, map=0x7f8cb3b3f170) at ../sysdeps/x86_64/dl-machine.h:300
    #3 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>, nrelative=<optimized out>,
    relsize=<optimized out>, reladdr=<optimized out>, scope=<optimized out>, map=0x7f8cb3b3f170)
    at ./elf/do-rel.h:147
    #4 _dl_relocate_object (l=l@entry=0x7f8cb3b3f170, scope=<optimized out>, reloc_mode=<optimized out>,
    consider_profiling=<optimized out>, consider_profiling@entry=0) at ./elf/dl-reloc.c:301
    #5 0x00007f8cb3b5e6e9 in dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>,
    auxv=<optimized out>) at ./elf/rtld.c:2318
    #6 0x00007f8cb3b5af0f in _dl_sysdep_start (start_argptr=start_argptr@entry=0x7ffe17e402e0,
    dl_main=dl_main@entry=0x7f8cb3b5c900 <dl_main>) at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0) at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```
  4. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -246,6 +246,31 @@ root@debian:~# perl -pe 's/\xF3\x0F\x1E\xFA\x55\x48\x89\xF5\x4C\x89\xCE/\xEB\xFE
    # env -i LC_LANG=C LD_PRELOAD=$PWD/liblzma.so.5.6.1 /usr/sbin/sshd -h
    ```

    2b. or use this gdbinit file to do it all at once
    ```shell
    # cat gdbinit
    set confirm off
    unset env
    set env LD_PRELOAD=/root/sshd/liblzma.so.5.6.1
    set env LANG=C
    file /usr/sbin/sshd
    set args -h
    set disassembly-flavor intel
    set confirm on
    set startup-with-shell off

    show env
    show args

    # gdb -x gdbinit
    (gdb) r
    Starting program: /usr/sbin/sshd -h
    ^C <-- send CTRL-C
    Program received signal SIGINT, Interrupt.
    0x00007ffff7f8a7f0 in ?? ()
    ```


    3. Attach to the frozen process with your favourite debugger (`gdb attach pid`)
    ```
    (gdb) bt
  5. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -234,7 +234,7 @@ __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_elf_info *elf_inf
    Note how, instead of `size`, the malware passes an EncodedStringID instead
    ##### Dynamic analysis
    ## Dynamic analysis
    1. Replace the `endbr64` in `get_cpuid` with a `jmp .` ("\xeb\xfe")
    ```shell
  6. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 66 additions and 1 deletion.
    67 changes: 66 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -234,4 +234,69 @@ __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_elf_info *elf_inf
    Note how, instead of `size`, the malware passes an EncodedStringID instead
    #####
    ##### Dynamic analysis
    1. Replace the `endbr64` in `get_cpuid` with a `jmp .` ("\xeb\xfe")
    ```shell
    root@debian:~# cat /usr/lib/x86_64-linux-gnu/liblzma.so.5.6.1 > liblzma.so.5.6.1
    root@debian:~# perl -pe 's/\xF3\x0F\x1E\xFA\x55\x48\x89\xF5\x4C\x89\xCE/\xEB\xFE\x90\x90\x55\x48\x89\xF5\x4C\x89\xCE/g' -i liblzma.so.5.6.1
    ```
    2. Force sshd to use the modified library with `LD_PRELOAD`
    ```
    # env -i LC_LANG=C LD_PRELOAD=$PWD/liblzma.so.5.6.1 /usr/sbin/sshd -h
    ```

    3. Attach to the frozen process with your favourite debugger (`gdb attach pid`)
    ```
    (gdb) bt
    #0 0x00007f8cb3b067f0 in ?? () from /root/sshd/liblzma.so.5.6.1
    #1 0x00007f8cb3b08c29 in lzma_crc32 () from /root/sshd/liblzma.so.5.6.1
    #2 0x00007f8cb3b4ffab in elf_machine_rela (skip_ifunc=<optimized out>,
    reloc_addr_arg=0x7f8cb3b3dda0 <lzma_crc32@got[plt]>,
    version=<optimized out>, sym=0x7f8cb3b03018, reloc=0x7f8cb3b04fc8,
    scope=0x7f8cb3b3f4f8, map=0x7f8cb3b3f170)
    at ../sysdeps/x86_64/dl-machine.h:300
    #3 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>,
    nrelative=<optimized out>, relsize=<optimized out>,
    reladdr=<optimized out>, scope=<optimized out>, map=0x7f8cb3b3f170)
    at ./elf/do-rel.h:147
    #4 _dl_relocate_object (l=l@entry=0x7f8cb3b3f170, scope=<optimized out>,
    reloc_mode=<optimized out>, consider_profiling=<optimized out>,
    consider_profiling@entry=0) at ./elf/dl-reloc.c:301
    #5 0x00007f8cb3b5e6e9 in dl_main (phdr=<optimized out>, phnum=<optimized out>,
    user_entry=<optimized out>, auxv=<optimized out>) at ./elf/rtld.c:2318
    #6 0x00007f8cb3b5af0f in _dl_sysdep_start (
    start_argptr=start_argptr@entry=0x7ffe17e402e0,
    dl_main=dl_main@entry=0x7f8cb3b5c900 <dl_main>)
    at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0)
    at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    (gdb) bt
    #0 0x00007f8cb3b067f0 in ?? () from /root/sshd/liblzma.so.5.6.1
    #1 0x00007f8cb3b08c29 in lzma_crc32 () from /root/sshd/liblzma.so.5.6.1
    #2 0x00007f8cb3b4ffab in elf_machine_rela (skip_ifunc=<optimized out>,
    reloc_addr_arg=0x7f8cb3b3dda0 <lzma_crc32@got[plt]>, version=<optimized out>, sym=0x7f8cb3b03018,
    reloc=0x7f8cb3b04fc8, scope=0x7f8cb3b3f4f8, map=0x7f8cb3b3f170) at ../sysdeps/x86_64/dl-machine.h:300
    #3 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>, nrelative=<optimized out>,
    relsize=<optimized out>, reladdr=<optimized out>, scope=<optimized out>, map=0x7f8cb3b3f170)
    at ./elf/do-rel.h:147
    #4 _dl_relocate_object (l=l@entry=0x7f8cb3b3f170, scope=<optimized out>, reloc_mode=<optimized out>,
    consider_profiling=<optimized out>, consider_profiling@entry=0) at ./elf/dl-reloc.c:301
    #5 0x00007f8cb3b5e6e9 in dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>,
    auxv=<optimized out>) at ./elf/rtld.c:2318
    #6 0x00007f8cb3b5af0f in _dl_sysdep_start (start_argptr=start_argptr@entry=0x7ffe17e402e0,
    dl_main=dl_main@entry=0x7f8cb3b5c900 <dl_main>) at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0) at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```
  7. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -86,7 +86,7 @@
    - `Llzma_index_encoder_init_1` -> `process_shared_libraries_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    - func @0x7620 : It does indirect calls on the vtable configured by `backdoor_vtbl_init`, and is called by the `RSA_public_decrypt` upon certain conditions are met
    - func @0x7620 : It does indirect calls on the vtable configured by `backdoor_vtbl_init`, and is called by the `RSA_public_decrypt` hook (func#1) upon certain conditions are met
    Software Breakpoint check, method 1
    -----
  8. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,8 @@
    - `Lx86_code_part_0` -> `code_dasm`
    -----

    - `Llzma_delta_decoder_init_part_0` -> `backdoor_ctx_init`
    - `Llzma_delta_decoder_init_part_0` -> `backdoor_vtbl_init`
    - It sets up a vtable with core functions used by the backdoor

    - `Lstream_decoder_memconfig_part_1` -> `get_lzma_allocator`

    @@ -85,6 +86,8 @@
    - `Llzma_index_encoder_init_1` -> `process_shared_libraries_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    - func @0x7620 : It does indirect calls on the vtable configured by `backdoor_vtbl_init`, and is called by the `RSA_public_decrypt` upon certain conditions are met
    Software Breakpoint check, method 1
    -----
  9. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -81,8 +81,8 @@
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    - `Llzma_index_stream_flags_0` -> `process_shared_libraries`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_library_map` to traverse it
    - `Llzma_index_encoder_init_1` -> `process_shared_library_map`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_libraries_map` to traverse it
    - `Llzma_index_encoder_init_1` -> `process_shared_libraries_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    Software Breakpoint check, method 1
  10. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -80,6 +80,10 @@
    ----
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    - `Llzma_index_stream_flags_0` -> `process_shared_libraries`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_library_map` to traverse it
    - `Llzma_index_encoder_init_1` -> `process_shared_library_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    Software Breakpoint check, method 1
    -----
  11. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@
    - `Llzma_lzma_optimum_fast_0` -> `install_entries`
    - `Llzip_decoder_memconfig_part_0` -> `installed_func_0`
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://gist.github.com/q3k))
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://github.com/q3k))
    - `Lindex_decode_1` -> `installed_func_2`
    - `Lindex_encode_1` -> `installed_func_3`
    - `Llzma2_decoder_end_1` -> `apply_one_entry_ex`
  12. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@
    - `Llzma_lzma_optimum_fast_0` -> `install_entries`
    - `Llzip_decoder_memconfig_part_0` -> `installed_func_0`
    - `Llzma_index_stream_size_1` -> `installed_func_1`
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://gist.github.com/q3k))
    - `Lindex_decode_1` -> `installed_func_2`
    - `Lindex_encode_1` -> `installed_func_3`
    - `Llzma2_decoder_end_1` -> `apply_one_entry_ex`
  13. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -199,7 +199,7 @@ The third `lzma_allocator` field, `opaque`, is abused to pass information about
    This is highlighted quite well by function `Llzma_index_buffer_encode_0`:

    ```c
    __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_segment *elf_info, struct_ctx *ctx)
    __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_elf_info *elf_info, struct_ctx *ctx)
    {
    _QWORD *lzma_allocator;
    __int64 result;
  14. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -195,7 +195,7 @@ The malware initializes it in `parse_elf_init` (TODO: find which functions are u
    ++ctx->num_imports;
    ```

    The third `lzma_allocator` field, `opaque`, is abused to pass information about the loaded ELF file "fake allocator" functions.
    The third `lzma_allocator` field, `opaque`, is abused to pass information about the loaded ELF file to the "fake allocator" function.
    This is highlighted quite well by function `Llzma_index_buffer_encode_0`:

    ```c
  15. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 20 additions and 12 deletions.
    32 changes: 20 additions & 12 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -195,23 +195,31 @@ The malware initializes it in `parse_elf_init` (TODO: find which functions are u
    ++ctx->num_imports;
    ```

    The third `lzma_allocator` field, `opaque`, is abused to pass additional data to the "allocator" functions, e.g. (in `Llzma_index_buffer_encode_0`):
    The third `lzma_allocator` field, `opaque`, is abused to pass information about the loaded ELF file "fake allocator" functions.
    This is highlighted quite well by function `Llzma_index_buffer_encode_0`:

    ```c
    __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_segment *elf_info, struct_ctx *ctx)
    {
    _QWORD *lzma_allocator;
    __int64 result;
    __int64 fn_read;
    __int64 fn_errno_location;

    lzma_allocator = get_lzma_allocator();
    result = parse_elf(*a1, a2);
    result = parse_elf(*p_elf, elf_info); // reads elf into elf_info
    if ( (_DWORD)result )
    {
    lzma_allocator[2] = a2; // <-- sets the `opaque` field to some data that will be used by the fake allocator function
    v6 = lzma_alloc(STR_read_, lzma_allocator);
    *(_QWORD *)(a3 + 72) = v6;
    if ( v6 )
    ++*(_DWORD *)a3;
    v7 = lzma_alloc(STR___errno_location_, lzma_allocator);
    *(_QWORD *)(a3 + 80) = v7;
    if ( v7 )
    ++*(_DWORD *)a3;
    return *(_DWORD *)a3 == 2;
    lzma_allocator[2] = elf_info; // set opaque field to the parsed elf info
    fn_read = lzma_alloc(STR_read_, lzma_allocator);
    ctx->fn_read = fn_read;
    if ( fn_read )
    ++ctx->num_imports;
    fn_errno_location = lzma_alloc(STR___errno_location_, lzma_allocator);
    ctx->fn_errno_location = fn_errno_location;
    if ( fn_errno_location )
    ++ctx->num_imports;
    return ctx->num_imports == 2; // true if we found both imports
    }
    return result;
    }
  16. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -195,7 +195,7 @@ The malware initializes it in `parse_elf_init` (TODO: find which functions are u
    ++ctx->num_imports;
    ```

    The third field, `opaque`, is used to pass additional data to the functions, e.g. (in `Llzma_index_buffer_encode_0`):
    The third `lzma_allocator` field, `opaque`, is abused to pass additional data to the "allocator" functions, e.g. (in `Llzma_index_buffer_encode_0`):

    ```c
    lzma_allocator = get_lzma_allocator();
  17. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -182,8 +182,8 @@ char *get_lzma_allocator_addr()
    The interface for `lzma_allocator` can be viewed for example here: https://github.com/frida/xz/blob/e70f5800ab5001c9509d374dbf3e7e6b866c43fe/src/liblzma/api/lzma/base.h#L378-L440

    The malware initializes it in `parse_elf_init` (TODO: find which functions are used for `alloc` and `free`).
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function:
    e.g. from `resolve_imports`:
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function.
    this is used a lot in `resolve_imports`, e.g.:
    ```c
    system_func = lzma_alloc(STR_system_, lzma_allocator);
    ctx->system = system_func;
  18. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -77,6 +77,10 @@
    ----
    - `Lstream_decoder_mt_end_0` -> `get_lzma_allocator_addr`
    ----
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    Software Breakpoint check, method 1
    -----
    @@ -178,6 +182,19 @@ char *get_lzma_allocator_addr()
    The interface for `lzma_allocator` can be viewed for example here: https://github.com/frida/xz/blob/e70f5800ab5001c9509d374dbf3e7e6b866c43fe/src/liblzma/api/lzma/base.h#L378-L440

    The malware initializes it in `parse_elf_init` (TODO: find which functions are used for `alloc` and `free`).
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function:
    e.g. from `resolve_imports`:
    ```c
    system_func = lzma_alloc(STR_system_, lzma_allocator);
    ctx->system = system_func;
    if ( system_func )
    ++ctx->num_imports;
    shutdown_func = lzma_alloc(STR_shutdown_, lzma_allocator);
    ctx->shutdown = shutdown_func;
    if ( shutdown_func )
    ++ctx->num_imports;
    ```

    The third field, `opaque`, is used to pass additional data to the functions, e.g. (in `Llzma_index_buffer_encode_0`):

    ```c
  19. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -185,7 +185,7 @@ The third field, `opaque`, is used to pass additional data to the functions, e.g
    result = parse_elf(*a1, a2);
    if ( (_DWORD)result )
    {
    lzma_allocator[2] = a2;
    lzma_allocator[2] = a2; // <-- sets the `opaque` field to some data that will be used by the fake allocator function
    v6 = lzma_alloc(STR_read_, lzma_allocator);
    *(_QWORD *)(a3 + 72) = v6;
    if ( v6 )
  20. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -166,7 +166,8 @@ char *get_lzma_allocator_addr()
    char *mem;
    // Llookup_filter_part_0 holds the relative offset of `_Ldecoder_1` - 180h (0xC930)
    // by adding 0x160, it gets to 0xCA90 (Lx86_coder_destroy), which is subsequently used as scratch space for creating the `lzma_allocator` struct (data starts after 8 bytes, at 0xCA98, which is the beginning of a .data segment)
    // by adding 0x160, it gets to 0xCA90 (Lx86_coder_destroy), which is subsequently used as scratch space
    // for creating the `lzma_allocator` struct (data starts after 8 bytes, at 0xCA98, which is the beginning of a .data segment)
    mem = (char *)Llookup_filter_part_0;
    for ( i = 0; i <= 0xB; ++i )
    mem += 32;
  21. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 59 additions and 0 deletions.
    59 changes: 59 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -73,6 +73,10 @@
    - `Llzma_memlimit_get_1` -> `apply_method_2`
    ----
    ##### lzma allocator / call hiding
    ----
    - `Lstream_decoder_mt_end_0` -> `get_lzma_allocator_addr`
    Software Breakpoint check, method 1
    -----
    @@ -142,4 +146,59 @@ else if ( v13 && str_id == STR_EVP_PKEY_set__RSA_ )
    else if (str_id != STR_RSA_get__key_ || !v17 )
    ```

    ##### Hidden calls (via `lzma_alloc`)
    `lzma_alloc` has the following prototype:
    ```c
    extern void * lzma_alloc (size_t size , const lzma_allocator * allocator )
    ```
    The malware implements a custom allocator, which is obtained from `get_lzma_allocator` @ 0x4050
    ```c
    void *get_lzma_allocator()
    {
    return get_lzma_allocator_addr() + 8;
    }
    char *get_lzma_allocator_addr()
    {
    unsigned int i;
    char *mem;
    // Llookup_filter_part_0 holds the relative offset of `_Ldecoder_1` - 180h (0xC930)
    // by adding 0x160, it gets to 0xCA90 (Lx86_coder_destroy), which is subsequently used as scratch space for creating the `lzma_allocator` struct (data starts after 8 bytes, at 0xCA98, which is the beginning of a .data segment)
    mem = (char *)Llookup_filter_part_0;
    for ( i = 0; i <= 0xB; ++i )
    mem += 32;
    return mem;
    }
    ```

    The interface for `lzma_allocator` can be viewed for example here: https://github.com/frida/xz/blob/e70f5800ab5001c9509d374dbf3e7e6b866c43fe/src/liblzma/api/lzma/base.h#L378-L440

    The malware initializes it in `parse_elf_init` (TODO: find which functions are used for `alloc` and `free`).
    The third field, `opaque`, is used to pass additional data to the functions, e.g. (in `Llzma_index_buffer_encode_0`):

    ```c
    lzma_allocator = get_lzma_allocator();
    result = parse_elf(*a1, a2);
    if ( (_DWORD)result )
    {
    lzma_allocator[2] = a2;
    v6 = lzma_alloc(STR_read_, lzma_allocator);
    *(_QWORD *)(a3 + 72) = v6;
    if ( v6 )
    ++*(_DWORD *)a3;
    v7 = lzma_alloc(STR___errno_location_, lzma_allocator);
    *(_QWORD *)(a3 + 80) = v7;
    if ( v7 )
    ++*(_DWORD *)a3;
    return *(_DWORD *)a3 == 2;
    }
    return result;
    }
    ```

    Note how, instead of `size`, the malware passes an EncodedStringID instead

    #####
  22. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@
    - `Lsimple_coder_update_0` -> `table_get`
    - Retrieves the index of the encoded string given the plaintext string in memory
    - `Lcrc_init_0` -> `import_lookup`
    - `.Lcrc64_generic.0` -> `table_lookup_ex`
    - `.Lcrc64_generic.0` -> `import_lookup_ex`
    -----

    ##### Anti RE and x64 code Dasm
  23. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@
    - `Llz_stream_decode` -> `count_1_bits`
    - `Lsimple_coder_update_0` -> `table_get`
    - Retrieves the index of the encoded string given the plaintext string in memory
    - `Lcrc_init_0` -> `table_lookup_multi`
    - `Lcrc_init_0` -> `import_lookup`
    - `.Lcrc64_generic.0` -> `table_lookup_ex`
    -----

    @@ -141,3 +141,5 @@ else if ( v13 && str_id == STR_EVP_PKEY_set__RSA_ )
    ...
    else if (str_id != STR_RSA_get__key_ || !v17 )
    ```

    #####
  24. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -131,7 +131,7 @@ __int64 backdoor_init(rootkit_ctx *ctx, DWORD *prev_got_ptr)
    ```
    ----
    ##### Name matching (function 0x28C0)
    ##### Function Name matching (function 0x28C0)
    ```c
    str_id = table_get(a6, 0LL);
    ...
  25. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -45,7 +45,7 @@
    // locate elf header
    while ( 1 )
    {
    if ( (unsigned int)table_get(ehdr, 0LL) == 0x300 )
    if ( (unsigned int)table_get(ehdr, 0LL) == STR__ELF ) // 0x300
    break; // found
    ehdr -= 64; // backtrack and try again
    if ( ehdr == start_pointer )
  26. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 13 additions and 2 deletions.
    15 changes: 13 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -94,7 +94,7 @@ __int64 check_software_breakpoint(_DWORD *code_addr, __int64 a2, int a3)
    ```

    ----
    Function backdoor_init (0xA784
    Function backdoor_init (0xA7849)

    ```c
    __int64 backdoor_init(rootkit_ctx *ctx, DWORD *prev_got_ptr)
    @@ -129,4 +129,15 @@ __int64 backdoor_init(rootkit_ctx *ctx, DWORD *prev_got_ptr)
    return runtime_offset;
    }
    ```
    ----
    ----
    ##### Name matching (function 0x28C0)
    ```c
    str_id = table_get(a6, 0LL);
    ...
    if ( str_id == STR_RSA_public_decrypt_ && v11 )
    ...
    else if ( v13 && str_id == STR_EVP_PKEY_set__RSA_ )
    ...
    else if (str_id != STR_RSA_get__key_ || !v17 )
    ```
  27. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -38,6 +38,20 @@
    - `Llzma_stream_header_encode_part_0` -> `get_ehdr_address`
    - `Lparse_bcj_0` -> `process_elf_seg`
    - `Llzma_simple_props_size_part_0` -> `is_gnu_relro`


    ##### Stealthy ELF magic verification
    ```c
    // locate elf header
    while ( 1 )
    {
    if ( (unsigned int)table_get(ehdr, 0LL) == 0x300 )
    break; // found
    ehdr -= 64; // backtrack and try again
    if ( ehdr == start_pointer )
    goto not_found;
    }
    ```
    ----
    - `Llzma_stream_flags_compare_1` -> `get_rodata_ptr`
  28. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,7 @@

    - `Llz_stream_decode` -> `count_1_bits`
    - `Lsimple_coder_update_0` -> `table_get`
    - Retrieves the index of the encoded string given the plaintext string in memory
    - `Lcrc_init_0` -> `table_lookup_multi`
    - `.Lcrc64_generic.0` -> `table_lookup_ex`
    -----
  29. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,11 @@
    ##### Prefix Trie (https://social.hackerspace.pl/@q3k/112184695043115759)
    - `Llzip_decode_1` -> `table1`
    - `Lcrc64_clmul_1` -> `table2`

    - `Llz_stream_decode` -> `count_1_bits`
    - `Lsimple_coder_update_0` -> `table_get`
    - `Lcrc_init_0` -> `table_lookup_multi`
    - `.Lcrc64_generic.0` -> `table_lookup_ex`
    -----

    ##### Anti RE and x64 code Dasm
    @@ -31,10 +36,6 @@

    - `Llzma_stream_header_encode_part_0` -> `get_ehdr_address`
    - `Lparse_bcj_0` -> `process_elf_seg`
    - `Lsimple_coder_update_0` -> `table_get`
    - `Lcrc_init_0` -> `table_lookup_multi`
    - `.Lcrc64_generic.0` -> `table_lookup_ex`
    - `Llz_stream_decode` -> `count_1_bits`
    - `Llzma_simple_props_size_part_0` -> `is_gnu_relro`
    ----

  30. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -25,11 +25,12 @@

    ----
    ##### ELF parsing
    - `Lget_literal_price_part_0` -> `parse_elf`
    - `Lparse_bcj_0` -> `process_elf_seg`
    - `Lmicrolzma_encoder_init_1` -> `parse_elf_init`
    - `Llzma_filter_decoder_is_supported.part.0` -> `parse_elf_invoke`
    - `Lmicrolzma_encoder_init_1` -> `parse_elf_init`
    - `Lget_literal_price_part_0` -> `parse_elf`

    - `Llzma_stream_header_encode_part_0` -> `get_ehdr_address`
    - `Lparse_bcj_0` -> `process_elf_seg`
    - `Lsimple_coder_update_0` -> `table_get`
    - `Lcrc_init_0` -> `table_lookup_multi`
    - `.Lcrc64_generic.0` -> `table_lookup_ex`