2

Windows ホストでのライブ フォレンジック データ収集用の GUI フレームワークである Python スクリプトを作成しています。これまで、私が解決できなかった多くの問題はありませんでした。しかし、これは私を困惑させました。不適切な変数スコープに関連する問題である可能性がありますが、私の人生では、問題を見つけることができません。スクリプト自体は 2,000 行を超えるので、特に指示がない限り、関連する部分をコピーします。

機能を壊す行のどこかでコードに変更を加えました。以前は意図したとおりに完全に機能していましたが、今ではなぜ機能しないのかわかりません。これは間違いなく、将来プロジェクトにバージョン管理ソフトウェアを使用することにつながります。それは確かです。

奇妙なのは、スローされる例外がまったくないことです。

私がやろうとしているのは、実行したいオプション機能に対応する Tkinter Checkbutton ウィジェットをユーザーに選択させることです。Checkbutton ウィジェットごとに Tkinter IntVars をセットアップし、これらの IntVars を配列に配置して簡単に列挙できるようにしました。GUI には「開始」ボタンがあり、これを押すと start() 関数が開始されます。IntVar が 1 (選択を示す) に設定されている場合、この関数は配列内の Checkbutton IntVars を列挙し、関連する関数を実行する必要があります。

私のコードの他のすべての部分は意図したとおりに機能します。配列の作成に苦労しています。関数内でグローバルに宣言されていても、配列を変更できないようです。配列に手動で値を設定すると、意図したとおりに機能します。IntVars を反復処理して、「グローバル」配列を正しい値に設定することはできません。2 つの配列は決して変更されないようで、Checkbutton の IntVars が選択されても「1」に設定されていないかのように動作します。

#this is an array of integers corresponding to the checked
#state of desired filetypes for collection
filetypes = [0]*34

#this is an array of integers corresponding to optional collection items
optionalitems = [0]*10

#... snipped ...

#This function performs just fine if the filetypes array is set manually...
#extensions[] is an array containing file extension strings corresponding
# to the Checkbuttons on the fileSelector Toplevel widget.
#outputdirs[] is an array containing strings with a desired output directory.
def collectFiles():
    global filetypes

    n = 0
    print("Parsing checkboxes for file collection...\r\n")
    for item in filetypes:
        if item:
           print(extensions[n] + " selected...")
           #make output dir corresponding to the desired extension
           outputdest = cwd + "/output/" + computername + outputdirs[n]
           if not os.path.exists(outputdest):
               print(outputdest + " does not exist, creating...")
               os.makedirs(outputdest)
               print("Collection for " + outputdirs[n] + " beginning...")
               for drive in drives:
                   print("Searching drive " + drive + "...")
                   for filename in search(drive, extensions[n]):
                       try:
                           i = 2
                           #outpath = cwd + "/output/" + username + outputdirs[n]
                           tempbasename = os.path.basename(filename)
                           testpath = os.path.join(outputdest, tempbasename)
                           tempbasename2 = ""
                           while os.path.exists(testpath):
                               print(testpath + " exists in output directory.")
                               tempbasename2 = str(i) + "_" + tempbasename
                               i += 1
                               testpath = os.path.join(outputdest, tempbasename2)
                           shutil.copy2(filename,testpath)
                           print("Copied:\n\t" + filename + "\n to:\n\t" + testpath + "\n")
                           logfile.write(str(datetime.datetime.now()) + "- Copied:\r\n\t" + filename
                                     + "\r\n to:\r\n\t" + testpath + "\r\n\r\n")
                       except:
                           print("****Problem copying: " + filename + "\n")
                           logfile.write(str(datetime.datetime.now()) + "****Problem copying: " + filename
                                     + "\r\n\r\n")
                           pass
        n += 1

#... snipped ...

#here's where the oddness begins.
#The optionalitems array SHOULD be set outside of this
# function, before it is called.
def doOptionalCollection():
    x = 0
    for item in optionalitems:
        if item:
            optionfunctions[x]()
        x = x + 1

    collectFiles()

#this is the routine called when the "Start" button is pressed.
# The goal here is to enumerate the checkboxes on the GUI, and
# fill filetypes[] and optionalitems[] with values corresponding to
# whether or not the Checkbuttons are selected.
def start():
    global filetypes
    global optionalitems

    #... snipped ...
    #code here performs baseline forensic data collection,
    # and performs exactly as intended.
    #... snipped ...

    #get status of checkboxes and update optionalitems array.
    # optionArray is the Array of IntVars associated with Tkinter Checkbuttons
    # obj.get() --> 0 = unchecked, 1 = checked
    i = 0
    for obj in optionArray:
        optionalitems[i] = obj.get()
        i = i + 1

    doOptionalCollection()

#this is for a dialog-style window that pops up when a button is pressed.
# The dialog contains 34 checkboxes, each with a variable to hold the state.
def showFileSelector():
    global filetypes
    fs = Toplevel(master=root)
    fs.title("Collect files by extension...")
    #set up a grid based on the extensions dictionary keys.
    # have the grid wrap on the 6th element.

    #... snipped, setup of Checkbutton tkinter windgets ...

    buttonArray = [txtButton, pdfButton, logButton, docButton, docxButton,
               rarButton, zipButton, isoButton, jarButton, jpgButton,
               jpegButton, bmpButton, pngButton, gifButton, exeButton,
               pptButton, pptxButton, aviButton, mp4Button, movButton,
               flvButton, mpgButton, wmvButton, mp3Button, flacButton,
               wmaButton, m4aButton, wavButton, psdButton, rawButton,
               apkButton, szipButton, indexdatButton, thumbsdbButton]

    #using filetypes array, set the status of the checkbox.
    #this is helpful if the dialog is re-opened, it will
    # re-populate the dialog with previous selections.
    x = 0
    for item in buttonArray:
        if filetypes[x]:
            item.select()
        x = x + 1

    varArray = [txtvar, pdfvar, logvar, docvar, docxvar,
            rarvar, zipvar, isovar, jarvar, jpgvar,
            jpegvar, bmpvar, pngvar, gifvar, exevar,
            pptvar, pptxvar, avivar, mp4var, movvar,
            flvvar, mpgvar, wmvvar, mp3var, flacvar,
            wmavar, m4avar, wavvar, psdvar, rawvar,
            apkvar, szipvar, indexdatvar, thumbsdbvar]

    def accept():
        global filetypes
        #user has possibly chosen files to collect by extension.
        # iterate varArray to determine what files to collect,
        # and store the result in filetypes[].
        #This assignment also does not work.
        x = 0
        for var in varArray:
            #var.get() to get the values of checkboxes
            # 0 = unchecked
            # 1 = checked
            filetypes[x] = var.get()
            x = x + 1
        fs.destroy()


    def cancel():
        #user has decided to discard selections and close
        # the window.
        fs.destroy()

    #... snipped, GUI placement ...

#back to the base-level indentation (no indents... not inside any functions)

#... snipped, optional item GUI Checkbutton setup ....

optionArray = [productkeyvar, outlookvar,
               recyclebinvar, skypevar,
               prefetchvar, installlogvar,
               allmediavar, win7jumplistvar,
               win7thumbcachevar, recentfilesvar]

optionfunctions = [collectProductKeys, collectOutlookAttachments,
                   collectRecycleBin, collectSkypeHistory,
                   collectPrefetchFolder, collectDeviceInstallationLogs,
                   collectMediaFiles, collectWin7JumpList,
                   collectWin7ThumbnailCache, collectShortcutRecentFiles]

#... snipped, more GUI setup ...

#and then, the obligatory...
root.mainloop()

プロセス フローを簡素化するには、次の手順に従います。

  1. ユーザーは GUI でオプションを設定し、収集するファイル タイプも選択できます。ユーザーが収集するファイルタイプを選択した場合、 filetypes[] には目的の選択がすでに入力されている必要があります。この配列の変更は発生していないようです。

  2. ユーザーがスタート ボタンを押すと、スタート ボタン コマンドは start() 関数です。グローバルが定義されています。つまり、filetypes[] と optionalitems[] です。

  3. start() 内で、ベースライン フォレンジック コレクションが発生し、意図したとおりに機能します。

  4. 引き続き start() 内で、オプションのコレクションのチェックボックスのステータスを取得し、optionalitems[] にデータを入力します。この配列の変更は発生していないようです。

  5. start() は次に doOptionalCollection() を呼び出します。

  6. doOptionalCollection() には、定義されたグローバルもあります - filetypes[] と optionalitems[]。配列が列挙されると、初期値 (すべてゼロ) として読み取られます。これは、目的のコレクション関数が実行されていないことを意味します。

  7. doOptionalCollection() は、collectFiles() を呼び出します。

  8. collectFiles() にはグローバル定義があります。これは主に、関数自体で filetypes[] を解析していたときのアーティファクトです。filetypes 配列は常にすべてゼロであるため、コードで手動で設定しない限り、何も収集されません。

これは長い投稿です...ここに投稿するのは初めてなので、テキストの巨大な壁について事前にお詫び申し上げます。私は自分のコードから利益を得ようとしているわけではないので、意図した機能を完全に見たい場合は、コード ベースを共有しても問題ありません。興味のある方にパッケージ全体を提供できます。前もって感謝します!

4

0 に答える 0