Регулярное выражение Python groupdict возвращает отдельные символы вместо строк для групп

Я столкнулся с действительно запутанной проблемой с сопоставлением регулярных выражений в Python. У меня есть пара шаблонов регулярных выражений, которые отлично работают в инструментах отладки, таких как regex101:

Однако после реализации в скрипте шаблоны не соответствуют чему-либо, если только они не скомпилированы и не снабжены префиксом r перед открывающей кавычкой.

Даже в этом случае совпадения возвращают отдельные символы из группового словаря.

Может ли кто-нибудь дать какие-либо указания относительно того, что я делаю неправильно здесь?

deobf.py:

#!/bin/python
import sys
import getopt
import re
import base64

####################################################################################
#
# Setting up global vars and functions
#
####################################################################################

# Assemble Pattern Dictionary
pattern={}
pattern["HexOct"]=re.compile(r'([\"\'])(?P<obf_code>(\\[xX012]?[\dA-Fa-f]{2})*)\1')
pattern["Base64"]=re.compile(r'([\"\'])(?P<obf_code>[\dA-Za-z\/\+]{15,}={0,2})\1')

# Assemble more precise Pattern handling:
sub_pattern={}
sub_pattern["HexOct"]=re.compile(r'((?P<Hex>\\[xX][\dA-Fa-f]{2})|(?P<Oct>\\[012]?[\d]{2}))')

#print pattern # trying to Debug Pattern Dicts
#print sub_pattern # trying to Debug Pattern Dicts

# Global Var init
file_in=""
file_out=""
code_string=""
format_code = False

# Prints the Help screen
def usage():
    print "How to use deobf.py:"
    print "-----------------------------------------------------------\n"
    print "$ python deobf.py -i {inputfile.php} [-o {outputfile.txt}]\n"
    print "Other options include:"
    print "-----------------------------------------------------------"
    print "-f : Format - Format the output code with indentations"
    print "-h : Help - Prints this info\n"
    print "-----------------------------------------------------------"
    print "You can also use the long forms:"
    print "-i : --in"
    print "-o : --out"
    print "-f : --format"
    print "-h : --Help"

# Combination wrapper for the above two functions
def deHexOct(obf_code):
    match = re.search(sub_pattern["HexOct"],obf_code)
    if match:

        # Find and process Hex obfuscated elements
        for HexObj in match.groupdict()["Hex"]:
            print match.groupdict()["Hex"]
            print "Processing:"
            print HexObj.pattern
            obf_code.replace(HexObj,chr(int(HexObj),16))

        # Find and process Oct obfuscated elements
        for OctObj in set(match.groupdict()["Oct"]):
            print "Processing:"
            print OctObj
            obf_code.replace(OctObj,chr(int(OctObj),8))
    return obf_code

# Crunch the Data
def deObfuscate(file_string):
    # Identify HexOct sections and process
    match = re.search(pattern["HexOct"],file_string)
    if match:
        print "HexOct Obfuscation found."
        for HexOctObj in match.groupdict()["obf_code"]:
            print "Processing:"
            print HexOctObj
            file_string.replace(HexOctObj,deHexOct(HexOctObj))

    # Identify B64 sections and process
    match = re.search(pattern["Base64"],file_string)
    if match:
        print "Base64 Obfuscation found."
        for B64Obj in match.groupdict()["obf_code"]:
            print "Processing:"
            print B64Obj
            file_string.replace(B64Obj,base64.b64decode(B64Obj))

    # Return the (hopefully) deobfuscated string
    return file_string

# File to String
def loadFile(file_path):
    try:
        file_data = open(file_path)
        file_string = file_data.read()
        file_data.close()
        return file_string
    except ValueError,TypeError:
        print "[ERROR] Problem loading the File: " + file_path

# String to File
def saveFile(file_path,file_string):
    try:
        file_data = open(file_path,'w')
        file_data.write(file_string)
        file_data.close()
    except ValueError,TypeError:
        print "[ERROR] Problem saving the File: " + file_path

####################################################################################
#
# Main body of Script
#
####################################################################################
# Getting the args
try:
    opts, args = getopt.getopt(sys.argv[1:], "hi:o:f", ["help","in","out","format"])
except getopt.GetoptError:
    usage()
    sys.exit(2)

# Handling the args
for opt, arg in opts:
    if opt in ("-h", "--help"):
        usage()
        sys.exit()
    elif opt in ("-i", "--in"):
        file_in = arg
        print "Designated input file: "+file_in
    elif opt in ("-o", "--out"):
        file_out = arg
        print "Designated output file: "+file_out
    elif opt in ("-f", "--format"):
        format_code = True
        print "Code Formatting mode enabled"

# Checking the input   
if file_in =="":
    print "[ERROR] - No Input File Specified"
    usage()
    sys.exit(2)

# Checking or assigning the output
if file_out == "":
    file_out = file_in+"-deObfuscated.txt"
    print "[INFO] - No Output File Specified - Automatically assigned: "+file_out

# Zhu Li, Do the Thing!
code_string=loadFile(file_in)
deObf_String=deObfuscate(str(code_string))
saveFile(file_out,deObf_String)

Вывод консоли из моих отладочных отпечатков выглядит следующим образом:

C:\Users\NJB\workspace\python\deObf>deobf.py -i "Form 5138.php"
Designated input file: Form 5138.php
[INFO] - No Output File Specified - Automatically assigned: Form 5138.php-deObfuscated.txt
HexOct Obfuscation found.
Processing:
\
Processing:
x
Processing:
6
Processing:
1
Processing:
\
Processing:
1
Processing:
5
Processing:
6
Processing:
\
Processing:
x
Processing:
7
Processing:
5
Processing:
\
Processing:
1
Processing:
5
Processing:
6
Processing:
\
Processing:
x
Processing:
6
Processing:
1

person Minothor    schedule 05.04.2016    source источник


Ответы (1)


Ваше регулярное выражение прекрасно сопоставляет группы, но затем вы перебираете символы в совпадающей группе.

Это дает строку, которую вы только что сопоставили: match.groupdict()["Hex"]

Это перебирает символы в строке:

for HexObj in match.groupdict()["Hex"]:

Вместо этого вы хотите повторять поиск, поэтому используйте re.finditer() вместо re.search(). Итак, что-то вроде:

def deHexOct(obf_code):
    for match in re.finditer(sub_pattern["HexOct"],obf_code):
        # Find and process Hex obfuscated elements
        groups = match.groupdict()
        hex = groups["Hex"]
        if hex:
            print "hex:", hex
            # do processing here
        oct = groups["Oct"]
        if oct:
            print "oct:", oct 
            # do processing here

Кроме того, r перед строкой просто мешает Python интерпретировать обратную косую черту как экранирование и необходимо для регулярных выражений, поскольку они также используют обратную косую черту для экранирования. Альтернативой может быть удвоение каждой обратной косой черты в вашем регулярном выражении; тогда вам не понадобится префикс r, но регулярное выражение может стать еще менее читаемым.

person Duncan    schedule 05.04.2016
comment
Спасибо за указание на проблему с символом, но, к сожалению, я получаю сообщение об ошибке с findall, в котором говорится, что возвращенный объект соответствия не имеет метода groupdict(). Интересно, что печать показывает, что это диктофон без ключей. Мне немного больше повезло с finditer(), но я все еще возился. - person Minothor; 05.04.2016
comment
Извините, здесь должно было быть сказано «искатель». finditer возвращает объекты соответствия, findall просто возвращает строки. - person Duncan; 05.04.2016
comment
С этим изменением у меня появилась функциональность! Теперь мне просто нужно сократить свою работу до самого СУХОГО возможного решения. - person Minothor; 05.04.2016