绿斑

本文Python代码针对绿斑文件窃取器PE中的C2通过异或解密提取。
样本来源:
从绿斑APT组织的文件窃取器理解加密流量,生产流量规则以及密文还原

代码

image.png

反汇编

IDA

  1. .text:00402B89 lea eax, [esp+900h+encryptedC2]
  2. .text:00402B90 push 37h ; '7' ; Size
  3. .text:00402B92 push offset encryptedC2 ; Src
  4. .text:00402B97 push eax ; void *
  5. .text:00402B98 call _memmove
  6. .text:00402B9D movups xmm0, xmmword ptr [esp+90Ch+encryptedC2]
  7. .text:00402BA5 add esp, 0Ch
  8. .text:00402BA8 xor ecx, ecx
  9. .text:00402BAA movups xmm1, key_422918
  10. .text:00402BB1 mov edx, 17h
  11. .text:00402BB6 pxor xmm1, xmm0
  12. .text:00402BBA movups xmm0, xmmword ptr [esp+900h+var_848]
  13. .text:00402BC2 movups xmmword ptr [esp+900h+encryptedC2], xmm1
  14. .text:00402BCA movups xmm1, xmmword_422928
  15. .text:00402BD1 pxor xmm1, xmm0
  16. .text:00402BD5 movups xmmword ptr [esp+900h+var_848], xmm1
  17. .text:00402BDD nop dword ptr [eax]
  18. .text:00402BE0
  19. .text:00402BE0 loc_402BE0: ; CODE XREF: _main+F3j
  20. .text:00402BE0 mov al, key_422938[ecx]
  21. .text:00402BE6 lea ecx, [ecx+1]
  22. .text:00402BE9 xor byte ptr [esp+ecx+900h+var_848+0Fh], al
  23. .text:00402BF0 sub edx, 1
  24. .text:00402BF3 jnz short loc_402BE0
地址 Hex 反汇编代码
402B89 8D8424 A8000000 LEA EAX,DWORD PTR SS:[ESP+0xA8]
402B90 6A 37 PUSH 0x37
402B92 68 9E284200 PUSH 0042289E
402B97 50 PUSH EAX
402B98 E8 13120000 CALL 00403DB0
402B9D 0F108424 B4000000 MOVUPS XMM0,DQWORD PTR SS:[ESP+0xB4]
402BA5 83C4 0C ADD ESP,0xC
402BA8 33C9 XOR ECX,ECX
402BAA 0F100D 18294200 MOVUPS XMM1,DQWORD PTR DS:[0x422918]
402BB1 BA 17000000 MOV EDX,0x17
402BB6 66:0FEFC8 PXOR MM1,MM0
402BBA 0F108424 B8000000 MOVUPS XMM0,DQWORD PTR SS:[ESP+0xB8]
402BC2 0F118C24 A8000000 MOVUPS DQWORD PTR SS:[ESP+0xA8],XMM1
402BCA 0F100D 28294200 MOVUPS XMM1,DQWORD PTR DS:[0x422928]
402BD1 66:0FEFC8 PXOR MM1,MM0
402BD5 0F118C24 B8000000 MOVUPS DQWORD PTR SS:[ESP+0xB8],XMM1
402BDD 0F1F00 NOP DWORD PTR DS:[EAX]
402BE0 8A81 38294200 MOV AL,BYTE PTR DS:[ECX+0x422938]
402BE6 8D49 01 LEA ECX,DWORD PTR DS:[ECX+0x1]
402BE9 30840C C7000000 XOR BYTE PTR SS:[ESP+ECX+0xC7],AL
402BF0 83EA 01 SUB EDX,0x1
402BF3 75 EB JNZ SHORT 00402BE0

参数inHEX

密文

密钥

密文长度

C2解密脚本

半自动-离线无文件版(手动输入数据,适配性高)

  1. key = [ 0x18, 0x92, 0x1A, 0x01, 0x98, 0xE6, 0xF3, 0x00, 0x59, 0x9F, 0xF0, 0x25, 0x19, 0xEC, 0xB1, 0x35, 0x23, 0x7F, 0x73, 0x3F, 0xED, 0xD3, 0xF7, 0x69 ]
  2. lenKey = len(key)
  3. C2Encrypted = [ 0x7A, 0xE0, 0x75, 0x76, 0xEB, 0x83, 0x81, 0x6E, 0x3C, 0xEB, 0xDE, 0x4C, 0x6D, 0x9F, 0xD0, 0x5A, 0x4F, 0x51, 0x10, 0x50, 0x80, 0xD3, 0xCF, 0x59 ]
  4. lenEncrypted = len(C2Encrypted)
  5. C2 = ''
  6. n0 = 0
  7. for i in range(lenEncrypted):
  8. xor = C2Encrypted[i] ^ key[i % lenKey]
  9. if (xor == 0):
  10. C2 += "\r\n"
  11. n0 += 1
  12. if (n0 == 2):
  13. break
  14. C2 += "端口:"
  15. else:
  16. C2 += chr(xor)
  17. print("域名:", C2)

全自动-读取PE文件(PE适配性差)

好麻烦啊,眼泪流下来,ImageBase打出来不对——更新:数据是十进制的,又忘了转十六进制,永远健忘,永远热泪盈眶😡😡😡

🙇‍♀️🙇‍♀️🙇‍♀️特别感谢杰哥帮我对数据进行转换🙇‍♀️🙇‍♀️🙇‍♀️

  1. import binascii
  2. import pefile
  3. import re
  4. # 小端序转大端序
  5. def Little2Big(strLittle):
  6. strBig = (int(strLittle, 16).to_bytes(4, 'little')).hex()[:6].upper()
  7. return strBig
  8. # 十六进制字符串处理为list
  9. def hexstr2list(strHex):
  10. time = int(len(strHex)/2)
  11. j = 0
  12. listHex = []
  13. for i in range(time):
  14. strHex2 = strHex[j : j+2]
  15. j += 2
  16. listHex.append(strHex2)
  17. return listHex
  18. # 1. 以十六进制读取PE样本
  19. def File2Read():
  20. filePE = open(pathFile, "rb")
  21. if(filePE):
  22. print("文件:\t\t\t成功读取文件")
  23. else:
  24. print("文件:\t\t无文件 / 文件无数据")
  25. exit(0)
  26. dataPE = filePE.read()
  27. global hexPE
  28. hexPE = binascii.b2a_hex(dataPE).decode('utf-8').upper()
  29. # 2. 正则匹配
  30. def HexRegVA():
  31. # 2.1 正则匹配:密文,密钥,长度
  32. '''
  33. # 原(compile + pattern),后(findall+转数据格式)更简洁点
  34. pattern = re.compile(r'A80000006A[0-9A-F]{2}68([0-9A-F]{6})0050E8[0-9A-F]+0F100D[0-9A-F]{6}00BA[0-9A-F]{2}000000660FEFC8')
  35. '''
  36. #findall写在一个表达式里返回的是tuple
  37. regData = list(re.findall(r'A80000006A[0-9A-F]{2}68([0-9A-F]{6})0050E8[0-9A-F]+0F100D([0-9A-F]{6})00BA([0-9A-F]{2})000000660FEFC8', hexPE)[0])
  38. # 2.1.1 密文
  39. addEncryptedString_Little = regData[0]
  40. print("密文inHex:\t\t", addEncryptedString_Little, type(addEncryptedString_Little))
  41. # 2.1.1 密钥
  42. addKey_Little = regData[1]
  43. print("密钥inHex:\t\t", addKey_Little, type(addKey_Little))
  44. # 2.1.2 长度
  45. global lenC2
  46. lenC2 = int(regData[2], 16) + 1
  47. print("C2明文长度:\t\t", lenC2, type(lenC2))
  48. # 2.2 VA
  49. # 2.2.1 密文
  50. encrypted_Big = Little2Big(addEncryptedString_Little)
  51. encryptedVA = int(encrypted_Big, 16)
  52. print("密文inVA:\t\t", hex(encryptedVA).upper(), type(encryptedVA))
  53. # 2.2.1 密钥
  54. key_Big = Little2Big(addKey_Little)
  55. keyVA = int(key_Big, 16)
  56. print("密钥inVA:\t\t", hex(keyVA).upper(), type(keyVA))
  57. # 2.3 PE数据
  58. filePE = pefile.PE(pathFile)
  59. # RAV = VA - ImageBase
  60. # FileOffset = RVA - VRk
  61. # 得:FileOffset = VA - ImageBase - VRk
  62. # 2.3.1 ImageBase
  63. intImageBase = filePE.OPTIONAL_HEADER.ImageBase
  64. ImageBase = int((hex(intImageBase))[2:], 16)
  65. print("ImageBase:\t\t", hex(ImageBase), type(ImageBase))
  66. # 2.3.2 RVA
  67. # 2.3.2.1 密文RVA
  68. encryptedRVA = (int(encryptedVA) - ImageBase)
  69. print("密文RVA:\t\t", hex(encryptedRVA).upper(), type(encryptedRVA))
  70. # 2.3.2.2 密钥RVA
  71. keyRVA = (int(keyVA) - ImageBase)
  72. print("密钥RVA:\t\t", hex(keyRVA).upper(), type(keyRVA))
  73. # 2.3.3 FileOffset
  74. # 2.3.3.1 密文FileOffset
  75. encryptedFileOffset = filePE.get_offset_from_rva(encryptedRVA)
  76. print("密文FileOffset:\t", hex(encryptedFileOffset).upper(), type(encryptedFileOffset))
  77. # 2.3.3.2 密钥FileOffset
  78. keyFileOffset = filePE.get_offset_from_rva(keyRVA)
  79. print("密钥FileOffset:\t", hex(keyFileOffset).upper(), type(keyFileOffset))
  80. # 2.4 从PE中取数据
  81. # 2.4.1 密文
  82. global encrypted
  83. encrypted = hexstr2list((hex(int(hexPE[2 * encryptedFileOffset : 2 * (encryptedFileOffset + lenC2)], 16))[2:].upper()))
  84. print("密文为:\t\t\t", encrypted)
  85. # 2.4.2 密钥
  86. global key
  87. key = hexstr2list((hex(int(hexPE[2 * keyFileOffset : 2 * (keyFileOffset + lenC2)], 16))[2:].upper()))
  88. print("密钥为:\t\t\t", key)
  89. # 3. 异或解密
  90. def Encrypted():
  91. C2 = ''
  92. n0 = 0
  93. for i in range(lenC2):
  94. xor = int(encrypted[i], 16) ^ int(key[i], 16)
  95. i += 2
  96. if (xor == 0):
  97. C2 += "\r\n"
  98. n0 += 1
  99. if (n0 == 2):
  100. break
  101. C2 += "端口:\t"
  102. else:
  103. C2 += chr(xor)
  104. print("域名:", C2)
  105. if __name__ == '__main__':
  106. pathFile = ".\\GreenSpot2020"
  107. File2Read()
  108. HexRegVA()
  109. Encrypted()
  110. # 【长度都是24,考虑通过第两次0x00后break】