Overview

According to FlashPoint

“RisePro” is a newly identified stealer written in C++ that appears to possess similar functionality to the stealer malware “Vidar.” RisePro targets potentially sensitive information on infected machines and attempts to exfiltrate it in the form of logs. “RisePro” is a newly identified stealer written in C++ that appears to possess similar functionality to the stealer malware “Vidar.” RisePro targets potentially sensitive information on infected machines and attempts to exfiltrate it in the form of logs.

RisePRO triggered a false positive for the Malpedia PrivateLoader yara rule and triggered the UnpacMe PrivateLoader config extractor. This led to correct string extraction from RisePRO even thought it is a separate malware. Are these related?!

References

Sample

  • 2cd2f077ca597ad0ef234a357ea71558d5e039da9df9958d0b8bd0efa92e74c9UnpacMe

Analysis

Both PrivateLoader and RisePRO use the same plaintext user agent string Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 and request header "Content-Type: application/x-www-form-urlencoded" also the string encryption algorithm is the same (xmm registers and xor intrinsic). Funny enough this causes a 100% overlap between the PrivateLoader Yara rule and RisePro.

Sample Identification

PrivateLoader yara rule matches on both PrivateLoader and RisePRO!

rule win_privateloader_w0 {
  meta:
    author =    "andretavare5"
    org =       "BitSight"
    date =      "2022-06-06"
    md5 =       "8f70a0f45532261cb4df2800b141551d"
    reference = "https://tavares.re/blog/2022/06/06/hunting-privateloader-pay-per-install-service"
    license =   "CC BY-NC-SA 4.0"

    malpedia_reference = "https://malpedia.caad.fkie.fraunhofer.de/details/win.privateloader"
    malpedia_version = "20220824"
    malpedia_license = "CC BY-NC-SA 4.0"
    malpedia_sharing = "TLP:WHITE"
  strings:
    $code = { 66 0F EF (4?|8?) } // pxor xmm(1/0) - str chunk decryption
    $str =  "Content-Type: application/x-www-form-urlencoded" wide ascii
    $ua1 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" wide ascii
    $ua2 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36" wide ascii

  condition:
    uint16(0) == 0x5A4D and // MZ
    $str and
    any of ($ua*) and
    #code > 100
}

RisePro Yara Rule

We need new Yara rules for both PrivateLoader and RisePRO to differentiate the two.

The following rule was created by @c3rb3ru5d3d53c. She was using binlex and the rule is has decent fidelity for RisePro.

rule risepro {
    meta:
        author      = "c3rb3ru5d3d53c"
        description = "Detects RisePro"
        hash        = "2cd2f077ca597ad0ef234a357ea71558d5e039da9df9958d0b8bd0efa92e74c9"
        created     = "2023-06-18"
        os          = "windows"
        tlp         = "white"
        rev         = 1
    strings:
        $trait_0 = {
            8b ff 55 8b ec 83 ec 28 8d 4d ?? 56 57 6a 00 e8
            d6 f5 ff ff 8d 45 ?? 50 ff 75 ?? e8 b7 f9 ff ff
            59 59 8d 4d ?? 8b f0 8b fa e8 04 f6 ff ff 8b d7
            8b c6 5f 5e c9 c3}
        $trait_2 = {
            8b c7 83 ff 40 99 89 46 ?? 6a 3f 58 0f 4d f8 89
            56 ?? 8b 55 ?? 33 c0 33 c9 0f ab f8 83 ff 20 0f
            43 c8 33 c1 83 ff 40 0f 43 c8 09 44 1a ?? 09 4c
            1a ?? 66 83 4e ?? ?? 5f 8b c6 5e 5b c9 c3}
        $trait_4 = {
            8b 45 ?? 0f b7 c0 8d 04 48 0f b6 4c 1f ?? 89 45
            ?? 8b 45 ?? 0f b7 c0 83 c0 fc 66 c1 e1 08 89 45
            ?? 0f b6 44 1f ?? 66 0b c8 0f b6 44 1f ?? 66 03
            45 ?? 0f b7 c9 0f b7 d0 66 85 c9 74 69}
        $trait_5 = {
            8b 43 ?? 56 0f b7 73 ?? 2b d6 0f b7 48 ?? 8b c2
            33 d2 83 e9 04 f7 f1 0f b7 43 ?? 03 d6 3b d0 6a
            04 0f 47 d6 59 03 d1 5e 2b 7d ?? 03 d7 3b d1 5f
            0f 42 d1 66 8b c2 5b c9 c3}
        $trait_6 = {
            8a 4d ?? 8a 45 ?? 8a 55 ?? 8b 7d ?? c0 e9 04 80
            e1 03 c0 e0 02 02 c8 8a 45 ?? 88 4d ?? 8a ca c0
            e9 02 80 e1 0f c0 e0 04 c0 e2 06 02 c8 02 55 ??
            4b 88 4d ?? 88 55 ?? 85 db 7e 24}
        $trait_7 = {
            89 75 ?? ff 75 ?? e8 9b 0d 00 00 59 89 75 ?? ff
            75 ?? ff 75 ?? e8 c1 00 00 00 59 59 8b f0 89 75
            ?? c7 45 ?? ?? ?? ?? ?? e8 15 00 00 00 8b c6 8b
            4d ?? 64 89 0d 00 00 00 00 59 5f 5e 5b c9 c3}
        $trait_8 = {
            b6 45 f8 88 4d ?? c1 e9 08 03 c8 0f b6 45 ?? 88
            4d ?? c1 e9 08 03 c8 0f b6 45 ?? 88 4d ?? c1 e9
            08 03 c8 88 4d ?? c1 e9 08 00 4d ?? 83 c6 c0 8b
            c6 83 d7 ff 83 c3 40 85 ff 77 88}
        $trait_9 = {
            56 b2 2e 8b f1 e8 13 00 00 00 85 c0 74 03 40 eb
            02 8b c6 b2 2f 8b c8 5e e9 00 00 00 00 53 8a da
            eb 0d 3a c3 74 13 51 ff 15 ?? ?? ?? ?? 8b c8 8a
            01 84 c0 75 ed 33 c0 5b c3}
        $trait_10 = {
            56 8b f1 8b 4e ?? e8 3a 01 00 00 8b 4e ?? 8a d0
            85 c9 74 06 5e e9 24 00 00 00 b8 00 10 00 00 66
            85 46 ?? 74 0c 8b 46 ?? 8b 00 8b 48 ?? 8b 09 eb
            e3 6a 62 59 84 d2 0f b6 c2 5e 0f 44 c1 c3}
        $trait_11 = {
            56 8b f1 85 d2 74 34 53 8a 5a ?? f6 c3 04 75 2a
            83 7e ?? ?? 74 08 8b 02 f6 40 ?? ?? 74 1c 8b 4a
            ?? 80 cb 04 88 5a ?? 85 c9 78 0f 8b 42 ?? 6b d1
            28 03 50 ?? 80 6a ?? ?? 74 ce 5b 5e c3}
        $trait_12 = {
            56 8b f1 0f b7 46 ?? a9 60 24 00 00 74 2e a9 00
            20 00 00 74 0f 8b 16 e8 3a 00 00 00 8b ce 5e e9
            b0 ff ff ff a9 00 04 00 00 74 13 8b 4e ?? 85 c9
            74 0c ff 76 ?? ff d1 83 66 ?? ?? 59 5e c3}
        $trait_13 = {
            56 8b 71 ?? 57 6a 05 58 c7 06 40 42 0f 00 8b 51
            ?? eb 04 89 04 96 4a 3b d0 7d f8 33 ff 47 eb 09
            6a 0b 58 2b c2 89 04 96 4a 3b d7 7d f3 80 79 ??
            ?? 74 06 8b 41 ?? 89 3c 86 5f 5e c3}
        $trait_14 = {
            55 8b ec 8b 41 ?? 56 85 c0 74 14 ff 75 ?? ff 75
            ?? ff 75 ?? 52 ff 71 ?? ff d0 83 c4 14 eb 1d 8b
            45 ?? 33 f6 3b 75 ?? 75 10 ff 75 ?? 50 52 ff 71
            ?? ff 51 ?? 83 c4 10 eb 03 83 c8 ff 5e 5d c3}
        $trait_15 = {
            55 8b ec 83 ec 58 53 56 57 8b 7d ?? 33 db 89 4d
            ?? 33 f6 0f 57 c0 89 55 ?? 8b 0f 89 4d ?? 8a 41
            ?? 88 45 ?? 8b 01 89 45 ?? 33 c0 21 45 ?? 66 89
            45 ?? 8a 02 66 0f 13 45 ?? 3c 80 73 07}
        $trait_16 = {
            55 8b ec 83 ec 24 56 8d 75 ?? eb 1e 85 d2 74 1e
            8b 41 ?? 3b 42 ?? 73 0a 89 4e ?? 8b f1 8b 49 ??
            eb 08 89 56 ?? 8b f2 8b 52 ?? 85 c9 75 de 85 c9
            0f 44 ca 89 4e ?? 8b 45 ?? 5e c9 c3}
        $trait_17 = {
            8d 45 ?? 50 8d 45 ?? 50 8d 45 ?? 50 e8 b7 0a ff
            ff 8d 45 ?? 50 8d 45 ?? 50 e8 8a 14 ff ff 83 c4
            14 be 09 00 00 00 ?? ?? 8d 45 ?? 50 50 e8 76 14
            ff ff 83 c4 08 83 ee 01 75 ee}
        $trait_18 = {
            55 8b ec 83 e4 f8 51 56 8b f1 83 7e ?? ?? 75 23
            80 7e ?? ?? 72 1d a1 ?? ?? ?? ?? 85 c0 74 02 ff
            d0 8b ce e8 f8 df ff ff a1 ?? ?? ?? ?? 85 c0 74
            02 ff d0 8b ce e8 18 00 00 00 5e 8b e5 5d c3}
        $trait_19 = {
            55 8b ec 53 8b 5d ?? 56 57 8b 7d ?? 8d 47 ?? 50
            57 53 e8 b9 fd fe ff 8d 77 ?? 56 8d 47 ?? 50 8d
            43 ?? 50 e8 a8 fd fe ff 8d 47 ?? 50 8d 43 ?? 56
            50 e8 9a fd fe ff 83 c4 24 5f 5e 5b 5d c3}
        $trait_20 = {
            55 8b ec 51 56 8b 71 ?? 57 8b fa eb 22 3b 75 ??
            74 1a 85 ff 74 05 39 7e ?? 75 11 80 7e ?? ?? 75
            0b 8b ce e8 12 00 00 00 85 c0 75 09 8b 76 ?? 85
            f6 75 da 33 c0 5f 5e 59 5d c3}
        $trait_21 = {
            55 8b ec 51 56 57 8b fa 8b f1 eb 28 8b 4e ?? e8
            92 01 00 00 85 c0 75 19 3b 7e ?? 73 14 ff 75 ??
            8b d7 8b ce e8 14 00 00 00 59 85 c0 74 03 89 46
            ?? 8b 76 ?? 85 f6 75 d4 5f 5e 59 5d c3}
        $trait_22 = {
            55 8b ec 51 56 57 6a 01 8d 45 ?? 8b f1 50 8b fa
            57 ff 76 ?? ff 56 ?? 83 c4 10 83 f8 01 75 0d 8b
            45 ?? 0f b6 4d ?? 89 08 33 c0 eb 0d 57 ff 76 ??
            ff 56 ?? f7 d8 59 59 1b c0 5f 5e c9 c3}
        $trait_23 = {
            55 8b ec 51 51 53 56 8b 75 ?? 57 8b 46 ?? 8b 4e
            ?? 83 c0 fb 3b c1 0f 46 c8 8b 06 89 4d ?? 33 ff
            8b 40 ?? 89 45 ?? 8b 86 ?? ?? ?? ?? 8b 16 83 c0
            2a c1 f8 03 8b 5a ?? 3b d8 0f 82 04 01 00 00}
        $trait_24 = {
            53 8b dc 83 ec 08 83 e4 f0 83 c4 04 55 8b 6b ??
            89 6c 24 ?? 8b ec 83 ec 28 a1 ?? ?? ?? ?? 33 c5
            89 45 ?? 8b 4b ?? 8b 53 ?? 56 33 f6 89 55 ?? 57
            8b 7b ?? 81 f9 e0 00 00 00 0f 82 15 01 00 00}
        $trait_25 = {
            8d 45 ?? 50 8d 45 ?? 50 8d 45 ?? 50 e8 1d 0a ff
            ff 8d 45 ?? 50 8d 45 ?? 50 e8 f0 13 ff ff 83 c4
            14 be 31 00 00 00 8d 45 ?? 50 50 e8 de 13 ff ff
            83 c4 08 83 ee 01 75 ee}
        $trait_26 = {
            13 c0 03 d1 8b 4d ?? 83 d0 00 23 5d ?? 0b 5d ??
            c1 e3 08 c1 e9 12 0b d9 8b 4d ?? 03 d8 8b 45 ??
            51 03 59 ?? 89 38 89 70 ?? 89 50 ?? 89 58 ?? e8
            82 f8 ff ff 83 c4 08 5f 5e 5b 8b e5 5d c3}
        $trait_27 = {
            0f b6 47 ?? 0f b6 0f 83 c7 02 c1 e0 08 03 c8 8b
            c2 83 e2 3f 25 c0 03 00 00 83 c2 40 81 e1 ff 03
            00 00 03 d0 c1 e2 0a 03 d1 8b 4d ?? 8d 46 ?? 89
            45 ?? 81 fa 80 00 00 00 73 06}
        $trait_28 = {
            0f b6 0f 0f b6 47 ?? 83 c7 02 c1 e1 08 03 c8 8b
            c2 83 e2 3f 25 c0 03 00 00 83 c2 40 81 e1 ff 03
            00 00 03 d0 c1 e2 0a 03 d1 8b 4d ?? 8d 46 ?? 89
            45 ?? 81 fa 80 00 00 00 73 06}
    condition:
        uint16(0) == 0x5a4d and
        uint32(uint32(0x3c)) == 0x00004550 and
        7 of them
}

C2

The C2 domain is stored in plain text in RisePRO unlike PrivateLoader (where it is encrypted).

194.169.175[.]128

String Decryption

There are encrypted stack strings that are composed of the string data, and an accompanying XOR key. These are loaded onto the stack, then directly XOR decrypted.

X-Junior IDA Script

X-Junior has a script that we can try in IDA to decrypt these strings: GitHub Repo.

Andre Tavares Python Script

andretavare5 has a python script using capstone to decrypt the strings: Script Gist.

We have created our own hybrid of the two, which uses capstone for disassembly, but implements the logic from the IDA script...

XorStr Library

The string decryption looks a lot like this open source library xorstr. The following is an example of the library in use.

.text:00411E14 C7 44 24 08 25 7B 87 92                       mov     [esp+60h+var_58], 92877B25h
.text:00411E1C 0F 57 C0                                      xorps   xmm0, xmm0
.text:00411E1F C7 44 24 0C B6 10 A7 1F                       mov     [esp+60h+var_54], 1FA710B6h
.text:00411E27 8B 44 24 08                                   mov     eax, [esp+60h+var_58]
.text:00411E2B 8B 4C 24 0C                                   mov     ecx, [esp+60h+var_54]
.text:00411E2F 89 44 24 10                                   mov     dword ptr [esp+60h+var_50], eax
.text:00411E33 89 4C 24 14                                   mov     dword ptr [esp+60h+var_50+4], ecx
.text:00411E37 C7 44 24 08 D1 77 20 5B                       mov     [esp+60h+var_58], 5B2077D1h
.text:00411E3F C7 44 24 0C C5 36 32 7E                       mov     [esp+60h+var_54], 7E3236C5h
.text:00411E47 8B 44 24 08                                   mov     eax, [esp+60h+var_58]
.text:00411E4B 8B 4C 24 0C                                   mov     ecx, [esp+60h+var_54]
.text:00411E4F 89 44 24 18                                   mov     dword ptr [esp+60h+var_50+8], eax
.text:00411E53 89 4C 24 1C                                   mov     dword ptr [esp+60h+var_50+0Ch], ecx
.text:00411E57 C7 44 24 08 6D 1E EB FE                       mov     [esp+60h+var_58], 0FEEB1E6Dh
.text:00411E5F C7 44 24 0C D9 3C 87 48                       mov     [esp+60h+var_54], 48873CD9h
.text:00411E67 8B 44 24 08                                   mov     eax, [esp+60h+var_58]
.text:00411E6B 8B 4C 24 0C                                   mov     ecx, [esp+60h+var_54]
.text:00411E6F C7 44 24 08 BE 05 4C 3F                       mov     [esp+60h+var_58], 3F4C05BEh
.text:00411E77 89 44 24 40                                   mov     dword ptr [esp+60h+var_20], eax
.text:00411E7B C7 44 24 0C E4 36 32 7E                       mov     [esp+60h+var_54], 7E3236E4h
.text:00411E83 8B 44 24 08                                   mov     eax, [esp+60h+var_58]
.text:00411E87 89 4C 24 44                                   mov     dword ptr [esp+60h+var_20+4], ecx
.text:00411E8B 8B 4C 24 0C                                   mov     ecx, [esp+60h+var_54]
.text:00411E8F 89 44 24 48                                   mov     dword ptr [esp+60h+var_20+8], eax
.text:00411E93 8D 44 24 10                                   lea     eax, [esp+60h+var_50]
.text:00411E97 89 4C 24 4C                                   mov     dword ptr [esp+60h+var_20+0Ch], ecx
.text:00411E9B 8D 50 01                                      lea     edx, [eax+1]
.text:00411E9E 0F 28 4C 24 40                                movaps  xmm1, [esp+60h+var_20]
.text:00411EA3 66 0F EF 4C 24 10                             pxor    xmm1, [esp+60h+var_50]
.text:00411EA9 0F 29 4C 24 10                                movaps  [esp+60h+var_50], xmm1
.text:00411EAE 0F 29 44 24 20                                movaps  [esp+60h+var_40], xmm0
.text:00411EB3 C7 44 24 30 00 00 00 00                       mov     [esp+60h+var_30], 0
.text:00411EBB C7 44 24 34 00 00 00 00                       mov     [esp+60h+var_2C], 0

String Extraction

The string encryption is almost identical to privateloader, we had to adjust for registers that store immediates for multiple strings in a row. Also, there are situations where the stack string DWORDs are not combined in order. Currently we don't handle this, but the solution is to use the .dis memory displacement to determine the order of the the DWORDs.

Decryption Algorithm

  • select the first section in the PE file, assume this is the code
  • scan code for final pxor instruction and truncate at this instruction to remove extra code from scanning (handle packers with large first sections)
  • linear disassemble the full code block - not efficient
  • traverse assembly until pxor instruction is located
  • scan backwards until all immediate data is located for the xmm registers
  • decrypt xmm data, this is the string chunk
  • keep running tally of string chunks and combine if no instructions separate them
def unhex(hex_string):
    import binascii
    if type(hex_string) == str:
        return binascii.unhexlify(hex_string.encode('utf-8'))
    else:
        return binascii.unhexlify(hex_string)

def tohex(data):
    import binascii
    if type(data) == str:
        return binascii.hexlify(data.encode('utf-8'))
    else:
        return binascii.hexlify(data)
import pefile
import struct
from capstone import *
from capstone.x86 import *
import re
import time


def is_ascii(s):
    return all(c < 128 or c == 0 for c in s)


def xor(data, key):
    out = []
    for i in range(len(data)):
        out.append(data[i] ^ key[i % len(key)])
    return bytes(out)



def get_reg_data(instructions, reg_name):
    search_count = 0
    search_limit = 2000
    for inst in instructions:
        
        if search_count > search_limit:
            break
        search_count += 1
        
        if  inst.mnemonic == 'mov' and  inst.operands[0].type == X86_OP_REG  and  inst.operands[1].type == X86_OP_IMM:
            if inst.reg_name(inst.operands[0].reg) == reg_name:
                imm_value = inst.operands[1].value.imm
                data_chunk = struct.pack('<I',imm_value)
                return data_chunk
    return None


def get_data(instructions):
    data_chunks = []
    count = 0
    steps = 0
    steps_flag = 0
    flag_reg = 0
    search_count = 0
    search_limit = 400
    
    for inst_ptr in range(0,len(instructions)):
        inst = instructions[inst_ptr]
        steps +=1
        
        if search_count > search_limit:
            break
        search_count += 1
         
        if  inst.mnemonic == 'call':
            break

        # if  inst.mnemonic == 'mov' and  inst.operands[0].type == X86_OP_REG  and  inst.operands[1].type == X86_OP_IMM:
        #     flag_reg = 1
        
        if  inst.mnemonic == 'mov' and inst.operands[0].type == X86_OP_MEM and inst.operands[1].type == X86_OP_REG:
            reg_name = inst.reg_name(inst.operands[1].reg)
            #print(f"Scanning for {reg_name} data....")
            result = get_reg_data(instructions[inst_ptr:], reg_name)
            if result is None:
                #print("scanning failed")
                break
            #print(f"Found reg {reg_name} data {result}")
            data_chunks.append(result)
            count += 1
            steps = 0
            steps_flag = 1
         
        if  inst.mnemonic == 'mov' and ( (inst.operands[0].type == X86_OP_MEM and inst.operands[0].value.mem.disp != 0) or inst.operands[0].type == X86_OP_REG ) and inst.operands[1].type == X86_OP_IMM:
            imm_value = inst.operands[1].value.imm
            #print(hex(imm_value))
            if imm_value & 0xff000000 == 0:
                break
            data_chunk = struct.pack('<I',imm_value)
            data_chunks.append(data_chunk)

            count += 1
            steps = 0
            steps_flag = 1

        if steps == 16 and steps_flag:
            break
         #if steps == 6 and steps_flag:  # if you got some garbage string use this instead of the above
            #break
       
    
    enc_data = data_chunks[0:count//2][::-1]
    key = data_chunks[count//2:count][::-1]
    
    if flag_reg :
        enc_data = sum(zip(enc_data[1::2], enc_data[::2]), ())
        key = sum(zip(key[1::2], key[::2]), ())
    return b''.join(enc_data),b''.join(key)



def get_strings_from_inst(instructions):
    # search, build and decrypt strings
    strings = []
    addr = None
    string = ''

    for i, inst in enumerate(instructions):

        if inst.mnemonic == 'pxor':
        # if inst.address == 0x0045C8A0:
            #print(hex(inst.address))
            #try: # possible string decryption found  
            reversed_instruction_list = instructions[:i][::-1]
            encrypted_str, key = get_data(reversed_instruction_list)
            # print(f"str_len: {len(encrypted_str)}, key_len: {len(key)}")
            # print(encrypted_str.hex())
            # print(key.hex())

            if len(encrypted_str) == 0 or len(key) == 0:
                #print(f"Error at {hex(inst.address)} key or data is missing")
                continue

            if len(encrypted_str) != len(key):
                #print(f"Error at {hex(inst.address)} key and data not equal length")
                continue

            out = bytearray(encrypted_str[j] ^ key[j] for j in range(len(key)))

            #print(out)
            out = out.replace(b'\x00',b'')
            if len(out) == 0:
                continue
            #print(out.decode('utf-8'))

            if is_ascii(out):
                strings.append((inst.address,out.decode('utf-8')))
    return strings


SAMPLE_PATH = '/tmp/xorstr/work/rise.bin'
filename = SAMPLE_PATH
pe = pefile.PE(filename)
# Assume the first section is code
txt = pe.sections[0]

# TODO: we don't seem to be disassembling the full section?!!
image_base = pe.OPTIONAL_HEADER.ImageBase
section_rva = txt.VirtualAddress
section_offset = txt.PointerToRawData

section_data = txt.get_data()

pxor_egg = rb'\x66\x0F\xEF'
scan_end = section_data.rfind(pxor_egg)

section_data = section_data[:scan_end]



# disassemble .txt section
pe = pefile.PE(filename)
md = Cs(CS_ARCH_X86, CS_MODE_32) 
md.detail = True
md.skipdata = True
addr = 0



## Time starts
t = time.time()

# instructions = []
# for inst in md.disasm(section_data, image_base + section_rva):
#     instructions.append(inst)

# strings = get_strings_from_inst(instructions)

strings = []
for m in re.finditer(pxor_egg, section_data, re.DOTALL):
    scan_end = m.start()
    instructions = []
    for inst in md.disasm(section_data[scan_end-0x400:scan_end], image_base + section_rva + scan_end - 0x400):
        instructions.append(inst)
    strings += get_strings_from_inst(instructions)




# Benchmark 50.47584390640259 metastealer    
print(f"Benchmark {time.time() - t}")
                           
# print(len(strings))
string_dict = {}  
last_string = ''
for s in strings:
    if last_string != s[1]:
        string_dict[s[0]] = s[1]
    last_string = s[1]

for o in string_dict.keys():
    print(f"{hex(o)} {string_dict[o]}")

    
print("done")
Benchmark 11.684903144836426
0x45977b Vault_IE
0x459fe0 \FileZilla
0x45a526 IndexedDB
0x45afb0 \History
0x45b1f1 .txt
0x45b25f \
0x45bf57 name_on_card
0x45c051 card_number
0x45c555 exp_month
0x45d007 .txt
0x45d060 \
0x45d78b "rLd
0x45dfe8 .txt
0x45e056 \
0x45e560 expirationDate
0x45e924 httpOnly
0x45ee5c .txt
0x45eeca \
0x45f3d4 expirationDate
0x45f9d8 %s	%s	%s	%s	%llu	%s	%s

0x45fb81 wb
0x460383 
Storage: %s [%s]
URL: %s
Login: %s
Password: %s


0x460ec5 
Storage: %s
UserName: %s
E-MAIL: %s
Token: %s


0x4622e5 bhghoamapcdpbohphigoooaddinpkbai
0x4624d3 nkbihfbeogaeaoehlefnkodbefgpgknn
0x462909 kncchdigobghenbbaddojjnnaogfppfj
0x462b0c fihkakfobkmkjojpchpfgcmhfjnmnfpi
0x462d0f nkddgncdjgjfcddamfgcmfnlhccnimig
0x462edb nanjmdknhkinifnkgdcggcfnhdaammmj
0x463109 nlbmnnijcnlegkjjpcfjclmcfggfefdm
0x463318 amkmjjmmflddogmhpjloimipbofnfjih
0x46351b nhnkbkgjikgcigadomkphalanndcapjk
0x463721 cphhlgmgameodnhkjdmkpanlelnlohao
0x463924 fnjhmkhhmkbjkkabndcnnogagogbneec
0x463b27 kpfopkelmapcoipemfendmdcghnegimn
0x463d2a blnieiiffboillknjnepogjhkgnoapac
0x463f2d hpglfhgfnhbgpjdenjgmdgoeiappafln
0x4640f9 hnfanknocfeofbddgcijnmhnfnkdnaad
0x464327 jbdaocneiiinmjbjlgalhcelgbejmnid
0x464739 ffnbelfdoeiohenkjibnmadjiehjhajb
0x464984 fhbohimaelbohpjbbldcngcnapndodjp
0x464b87 ibnejdfjmmkpcnlpebklmnkoeoihofec
0x464d8a bfnaelmomeimhlpmgjnjophhpkkoljpa
0x464f69 fhilaheimglignddkjgofkcbgekhenbh
0x465eb0 aeachknmefphepccionboohckonoeemg
0x468aa6 vos wallt-
0x46a011 gojhcdgcpbpfigcaejpfhfegekdgiblk
0x46b485 e
0x46c565 "rLd
0x46c5aa ogies\BlackHaw
0x46d267 ion\NVIDIA GeFor
0x46d60c omePlus\User Dat
0x46df9a ChromiumViewer
0x46df20 dules\ChromiumVi
0x46e5af Torch
0x46ee1a Atom
0x46f412 %DESKTOP%
0x46f548 %DOCUMENTS%
0x47133e "rLd
0x4732ba \
0x47504d \profiles.ini
0x4754a3 \places.sqlite
0x476068 \profiles.ini
0x476509 \cookies.sqlite
0x4770ea \profiles.ini
0x47759d \places.sqlite
0x477a63 moz_places WHERE
0x4780f1 \profiles.ini
0x478ff2 \signons.sqlite
0x47a281 \
0x47a588 encrypted_key
0x47b86c email
0x47b8c3 username
0x47cef7 \
0x47decd encrypted_key
0x47f682 \
0x47f9df encrypted_key
0x47fbfb ~rLd
0x47febe encrypted_key
0x481b13 \
0x483135 encrypted_key
0x486542 ip
0x486c2c country
0x487430 demoInfo
0x487507 countryCode
0x487574 demoInfo
0x4875dd countryCode
0x487d6c country
0x487ead iso_code
0x48874a 1.1.1.1
0x4887b4 ZZ
0x488e95 mozglue.dll
0x488f6a softokn3.dll
0x489b97 \Monero\wallets
0x489ddf \Jaxx Liberty
0x48a000 \Local Storage
0x48abce \bither.db
0x48ad6b \ElectronCash
0x48b137 \Ethereum
0x48b310 \IndexedDB
0x48bd53 Florincoin
0x48be71 GoldCoin (GLD)
0x48c2fb digitalcoin
0x48c4cb Ledger Live
0x48cbb7 \Authy Desktop
0x48ce9a \Local Storage
0x48d948 SOFTWARE\Microsoft\Cryptography
0x48da64 MachineID: %s

0x48db55 GUID: %s

0x48de4a 
Path: %s

0x48dea4 Work Dir: %s


0x48e8b2 
Local Time: %d/%d/%d %d:%d:%d

0x48ea2e 
[Hardware]

0x48eb22 HARDWARE\DESCRIPTION\System\CentralProcessor\0
0x48ec7a Processor: %s

0x48ed73 RAM: %u MB

0x48efd1 
[Processes]

0x48f074 %s [%d]

0x48f462 DisplayVersion
0x4920ed InternetOpenA
done