Ghidra นั้นยอดเยี่ยมมากและฉันชอบสคริปต์ของฉันมากที่สุดเท่าที่จะทำได้ แต่การเขียนสคริปต์ Python ของ Ghidra นั้นขึ้นอยู่กับ Jython ซึ่งไม่ได้อยู่ในสถานะที่ดีในทุกวันนี้ การติดตั้งแพ็คเกจใหม่เป็นเรื่องยุ่งยากหากพวกเขาสามารถทำงานในสภาพแวดล้อมของ Jython และมันจะแย่ลงเมื่อ Python 2 ถูกปิดอย่างช้าๆ
ดังนั้น Ghidra Bridge จึงเป็นความพยายามที่จะหลีกเลี่ยงปัญหานั้น-แทนที่จะติดอยู่ใน Jython ตั้งค่าพร็อกซี RPC สำหรับวัตถุ Python ดังนั้นเราจึงสามารถโทรไปที่ Ghidra/Jython-Land เพื่อรับข้อมูลที่เราต้องการ
จุดมุ่งหมายคือการโปร่งใสที่สุดเท่าที่จะเป็นไปได้ดังนั้นเมื่อคุณตั้งค่าคุณไม่จำเป็นต้องรู้ว่าวัตถุนั้นอยู่ในพื้นที่หรือจากระยะไกล Ghidra - สะพานควรจัดการกับการรับ/การตั้งค่า/การโทรอย่างราบรื่น
หากคุณชอบสิ่งนี้คุณอาจสนใจในเครื่องมือด้านวิศวกรรมย้อนกลับอื่น ๆ :
ถ้าคุณชอบสิ่งนี้ จริงๆ อย่าลังเลที่จะซื้อกาแฟให้ฉัน: https://ko-fi.com/justfoxing
pip install ghidra_bridge
python -m ghidra_bridge.install_server ~/ghidra_scripts
สำหรับเชลล์แบบโต้ตอบที่ดีกว่าเช่น ipython หรือหากคุณต้องการไลบรารี Python 3 ในสภาพแวดล้อมแบบโต้ตอบคุณสามารถเริ่มต้นบริดจ์ในบริบทของเซสชัน GUI แบบโต้ตอบ
มิฉะนั้น:
คุณสามารถเรียกใช้ Ghidra Bridge เป็นสคริปต์การวิเคราะห์โพสต์สำหรับการวิเคราะห์แบบไม่มีหัวและจากนั้นทำการวิเคราะห์เพิ่มเติมจากลูกค้า ใช้ ghidra_bridge_server.py (ไม่ใช่ _background.py) สำหรับอันนี้ดังนั้นจึงไม่ออกจนกว่าคุณจะปิดสะพานลง
$ghidraRoot/support/analyzeHeadless <path to directory to store project> <name for project> -import <path to file to import> -scriptPath <install directory for the server scripts> -postscript ghidra_bridge_server.py
ดูที่ AnalyzeHeadlessReadMe.html ในการสนับสนุน/ ไดเรกทอรีของ Ghidra สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีเรียกใช้คำสั่ง AnalyzeHeadless หากจำเป็น
คุณสามารถเริ่มต้นบริดจ์ในสภาพแวดล้อมโดยไม่ต้องโหลดโปรแกรมใด ๆ เช่นหากคุณต้องการเข้าถึง API บางอย่างเช่น dataTypemanager ที่ไม่จำเป็นต้องมีการวิเคราะห์โปรแกรม
$ghidraRoot/support/pythonRun <install directory for the server scripts>/ghidra_bridge_server.py
จากสภาพแวดล้อมของลูกค้า Python:
import ghidra_bridge
with ghidra_bridge . GhidraBridge ( namespace = globals ()):
print ( getState (). getCurrentAddress (). getOffset ())
ghidra . program . model . data . DataUtilities . isUndefinedData ( currentProgram , currentAddress )หรือ
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ()) # creates the bridge and loads the flat API into the global namespace
print ( getState (). getCurrentAddress (). getOffset ())
# ghidra module implicitly loaded at the same time as the flat API
ghidra . program . model . data . DataUtilities . isUndefinedData ( currentProgram , currentAddress )คำเตือน: หากคุณทำงานในโหมดที่ไม่ใช่พื้นดินให้หลีกเลี่ยงการคลิกปุ่ม "ยกเลิก" บนป๊อปอัพสคริปต์เพราะจะทำให้ซ็อกเก็ตเซิร์ฟเวอร์อยู่ในสถานะที่ไม่ดีและคุณจะต้องปิด Ghidra อย่างสมบูรณ์เพื่อแก้ไข
หากต้องการปิดเซิร์ฟเวอร์อย่างหมดจดหากคุณทำขั้นตอนที่ 3 ในคำแนะนำการติดตั้งด้านบนให้คลิกเครื่องมือ-> Ghidra Bridge-> ปิดเครื่อง มิฉะนั้นให้เรียกใช้ GHIDRA_BRIDGE_SERVER_SHUTDOWN.PY สคริปต์จากโฟลเดอร์บริดจ์
หรือคุณสามารถโทรไปที่ remote_shutdown จากไคลเอนต์ที่เชื่อมต่อใด ๆ
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
b . remote_shutdown ()โปรดทราบว่าเมื่อทำงานเซิร์ฟเวอร์ Ghidra Bridge ให้การดำเนินการรหัสเป็นบริการอย่างมีประสิทธิภาพ หากผู้โจมตีสามารถพูดคุยกับสะพาน Port Ghidra กำลังดำเนินการอยู่
นอกจากนี้โปรดทราบว่าโปรโตคอลที่ใช้ในการส่งและรับข้อความ Ghidra Bridge นั้นไม่ได้เข้ารหัสและไม่ได้รับการตรวจสอบ-การโจมตีของบุคคลในกลางจะช่วยให้สามารถควบคุมคำสั่งและการตอบกลับได้อย่างสมบูรณ์
โดยค่าเริ่มต้นเซิร์ฟเวอร์ Ghidra Bridge จะฟังเฉพาะ LocalHost เพื่อลดพื้นผิวการโจมตีเล็กน้อย ฟังที่อยู่เครือข่ายภายนอกเท่านั้นหากคุณมั่นใจว่าคุณอยู่ในเครือข่ายที่ปลอดภัยที่จะทำเช่นนั้น นอกจากนี้ยังคงเป็นไปได้ที่ผู้โจมตีจะส่งข้อความไปยัง LocalHost (เช่นผ่าน JavaScript ที่เป็นอันตรายในเบราว์เซอร์หรือโดยใช้ประโยชน์จากกระบวนการที่แตกต่างกันและโจมตีสะพาน Ghidra เพื่อยกระดับสิทธิพิเศษ) คุณสามารถลดความเสี่ยงนี้ได้ด้วยการเรียกใช้ Ghidra Bridge จากเซิร์ฟเวอร์ Ghidra ที่มีสิทธิ์ลดลง (ผู้ใช้ที่ไม่ใช่ผู้บริหารหรือภายในคอนเทนเนอร์) โดยใช้งานเฉพาะเมื่อต้องการหรือโดยใช้ระบบที่เชื่อมต่อที่ไม่ใช่เครือข่าย
Ghidra Bridge ได้รับการออกแบบให้มีความโปร่งใส อย่างไรก็ตามหากคุณมีความสุขที่จะทำการเปลี่ยนแปลงและคุณพบกับการชะลอตัวที่เกิดจากการใช้การสืบค้นระยะไกลจำนวนมาก (เช่นบางอย่าง for function in currentProgram.getFunctionManager().getFunctions(): doSomething() สามารถลดลงได้ ซึ่งจะต้องใช้เพียงข้อความเดียวกลับไป
ตัวอย่างต่อไปนี้แสดงให้เห็นถึงการรับรายชื่อชื่อทั้งหมดของฟังก์ชั่นทั้งหมดในไบนารี:
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
name_list = b . remote_eval ( "[ f.getName() for f in currentProgram.getFunctionManager().getFunctions(True)]" )หากการประเมินของคุณต้องใช้เวลาสักครู่คุณอาจต้องใช้อาร์กิวเมนต์ TimeOut_override เพื่อเพิ่มระยะเวลาสะพานจะรอก่อนที่จะตัดสินใจว่าสิ่งต่าง ๆ ผิดพลาด
หากคุณต้องการจัดหาอาร์กิวเมนต์สำหรับการประเมินระยะไกลคุณสามารถให้อาร์กิวเมนต์คำหลักโดยพลการกับฟังก์ชันระยะไกล _eval ซึ่งจะถูกส่งผ่านไปยังบริบทการประเมินเป็นตัวแปรท้องถิ่น อาร์กิวเมนต์ต่อไปนี้ส่งผ่านในฟังก์ชัน:
import ghidra_bridge
b = ghidra_bridge . GhidraBridge ( namespace = globals ())
func = currentProgram . getFunctionManager (). getFunctions ( True ). next ()
mnemonics = b . remote_eval ( "[ i.getMnemonicString() for i in currentProgram.getListing().getInstructions(f.getBody(), True)]" , f = func )เพื่อให้ง่ายขึ้นโปรดทราบว่าบริบทการประเมินมี globals เดียวกันที่โหลดลงใน __Main__ ของสคริปต์ที่เริ่มต้นเซิร์ฟเวอร์ - ในกรณีของเซิร์ฟเวอร์ Ghidra Bridge ซึ่งรวมถึง API แบบแบนและค่าเช่น CurrentProgram
หากคุณมีการโทรช้าเป็นพิเศษในสคริปต์ของคุณอาจส่งผลกระทบต่อเวลาตอบสนองที่สะพานใช้เพื่อให้แน่ใจว่าการเชื่อมต่อไม่เสีย หากสิ่งนี้เกิดขึ้นคุณจะเห็นข้อ Exception: Didn't receive response <UUID> before timeout
มีสองตัวเลือกในการเพิ่มการหมดเวลา เมื่อสร้างบริดจ์คุณสามารถตั้งค่าการหมดเวลาในวินาทีด้วยอาร์กิวเมนต์ Response_timeOut (เช่น b = ghidra_bridge.GhidraBridge(namespace=globals(), response_timeout=20) ) ซึ่งจะใช้กับคำสั่งทั้งหมดที่วิ่งข้ามสะพาน อีกทางเลือกหนึ่งหากคุณต้องการเปลี่ยนการหมดเวลาสำหรับคำสั่งหนึ่งคำสั่งคุณสามารถใช้ Remote_eval ตามที่กล่าวไว้ข้าง b.remote_eval("[ f.getName() for f in currentProgram.getFunctionManager().getFunctions(True)]", timeout_override=20) หากคุณใช้ค่า -1 สำหรับข้อโต้แย้งเหล่านี้การหมดเวลาตอบสนองจะถูกปิดใช้งานและสะพานจะรอตลอดไปเพื่อให้การตอบกลับของคุณกลับมา - โปรดทราบว่าสิ่งนี้อาจทำให้สคริปต์ของคุณแขวนหากสะพานประสบปัญหา
หากคุณต้องการนำเข้าโมดูลจาก Ghidra-Side (เช่น Ghidra, Java, Docking Namespaces) คุณมีสองตัวเลือก
remote_module = b.remote_import("java.math.BigInteger") ) สิ่งนี้มีข้อได้เปรียบที่คุณสามารถควบคุมได้อย่างแน่นอนในการรับโมดูลระยะไกล (และสามารถรับโมดูลระยะไกลที่มีชื่อเดียวกับโมดูลท้องถิ่น) และเมื่อเปิดตัว แต่มันต้องใช้เวลาเพิ่มขึ้นอีกเล็กน้อยb = ghidra_bridge.GhidraBridge(namespace=globals(), hook_import=True) ) สิ่งนี้จะเพิ่มตะขอให้กับเครื่องจักรนำเข้าเช่นถ้าไม่มีอะไรสามารถเติมการนำเข้าได้สะพานจะพยายามจัดการ สิ่งนี้ช่วยให้คุณสามารถใช้ import ghidra.framework.model.ToolListener ไวยากรณ์หลังจากที่คุณเชื่อมต่อสะพาน สิ่งนี้มีข้อได้เปรียบที่อาจใช้งานได้ง่ายขึ้นเล็กน้อย (คุณยังต้องตรวจสอบให้แน่ใจว่าการนำเข้าเกิดขึ้นหลังจากเชื่อมต่อสะพาน) แต่ไม่อนุญาตให้คุณนำเข้าโมดูลระยะไกลที่มีชื่อเดียวกันกับโมดูลท้องถิ่น นอกจากนี้สะพานหลายแห่งที่มี hook_import = True จะพยายามแก้ไขการนำเข้าตามลำดับที่เชื่อมต่อซึ่งอาจไม่ใช่พฤติกรรมที่คุณต้องการโดยปกติแล้วสคริปต์ Ghidra จะได้รับอินสแตนซ์ของสถานะ Ghidra และตัวแปร* ปัจจุบัน (CurrentProgram, CurrentAddress ฯลฯ ) เมื่อเริ่มต้นครั้งแรกและไม่อัปเดตในขณะที่สคริปต์ทำงาน อย่างไรก็ตามหากคุณเรียกใช้ล่าม Ghidra Python นั่นจะอัปเดตสถานะด้วยคำสั่งทุกคำสั่งดังนั้น CurrentAddress จะตรงกับ GUI เสมอ
เพื่อสะท้อนสิ่งนี้ Ghidrabridge จะพยายามตรวจสอบโดยอัตโนมัติว่าคุณกำลังใช้งานไคลเอนต์ในสภาพแวดล้อมแบบโต้ตอบ (เช่น Python Interpreter, Ipython) หรือเพียงแค่จากสคริปต์ หากเป็นสภาพแวดล้อมแบบโต้ตอบมันจะลงทะเบียนผู้ฟังเหตุการณ์กับ Ghidra และดำเนินการ Shenanigans เบื้องหลังที่น่าสงสัยเพื่อให้แน่ใจว่ารัฐได้รับการปรับปรุงด้วยการเปลี่ยนแปลง GUI เพื่อทำตัวเหมือนล่าม Ghidra Python นอกจากนี้ยังจะแทนที่ help() ด้วยสิ่งที่เอื้อมมือไปใช้ความช่วยเหลือของ Ghidra ข้ามสะพานหากคุณให้วัตถุที่มีสะพาน
คุณไม่ควรสนใจเรื่องนี้ แต่ถ้าด้วยเหตุผลบางอย่างการตรวจจับอัตโนมัติไม่ได้ให้ผลลัพธ์ที่คุณต้องการคุณสามารถระบุอาร์กิวเมนต์บูลีน interactive_mode เมื่อสร้างไคลเอนต์ Ghidrabridge เพื่อบังคับให้เปิดหรือปิดตามที่ต้องการ
รหัสสะพาน RPC จริงถูกนำไปใช้ใน JFX-Bridge ตรวจสอบที่นั่นและไฟล์ปัญหาเฉพาะที่ไม่ใช่ GHIDRA ที่เกี่ยวข้องกับสะพานที่นั่น