Java Bytecode Analyzer ปรับแต่งผ่านกฎ JSON มันเป็นเครื่องมือบรรทัดคำสั่งที่ได้รับพา ธ ที่มีไฟล์ JAR หรือ WAR หนึ่งไฟล์ขึ้นไปวิเคราะห์โดยใช้กฎที่ให้ไว้และสร้างรายงาน HTML พร้อมผลลัพธ์
usage: java -jar cba-cli.jar [OPTIONS] -a DIRECTORY_TO_ANALYZE
-a,--analyze <pathToAnalyze> Path of the directory to run the
analysis.
-c,--checks <checks...> Space separated list of custom checks
that are going to be run in the analysis.
-f,--custom-file <customFile> Specify a file in JSON format to run
custom rules. Read more in
https://github.com/fergarrui/custom-bytecode-analyzer.
-h,--help Print this message.
-i,--items-report <maxItems> Max number of items per report. If the
number of issues found exceeds this
value, the report will be split into
different files. Useful if expecting too
many issues in the report. Default: 50.
-o,--output <outputDir> Directory to save the report. Warning -
if there are already saved reports in
this directory they will be overwritten.
Default is "report".
-v,--verbose-debug Increase verbosity to debug mode.
-vv,--verbose-trace Increase verbosity to trace mode - makes it slower, use it only when you need.
ไฟล์กฎสามารถระบุได้โดยใช้ -f,--custom-file ไฟล์อยู่ในรูปแบบ JSON และมีโครงสร้างดังต่อไปนี้:
final นอกจากนี้คุณยังสามารถตรวจสอบ net.nandgr.cba.custom.model.Rules.java เพื่อดูโครงสร้างในรหัส Java
มีกฎหลายข้อภายใต้ตัวอย่างไดเรกทอรี อย่างไรก็ตามด้านล่างนี้เป็นตัวอย่างที่ระบุไว้สำหรับทุกกฎ
หากเราต้องการค้นหาคลาสที่มี deserialization ที่กำหนดเองเราสามารถทำได้ค่อนข้างง่าย ชั้นเรียนกำหนด deserialization ที่กำหนดเองโดยการใช้ private void readObject(ObjectInputStream in) ดังนั้นเราจึงต้องค้นหาคลาสทั้งหมดที่กำหนดวิธีการนั้น มันจะเพียงพอที่จะกำหนดกฎเป็น:
{
"rules" : [{
"name" : " Custom deserialization " ,
"methods" : [{
"name" : " readObject " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectInputStream "
}]
}]
}]
} มันจะรายงานวิธีการที่มีการมองเห็น private readObject เป็นชื่อและพารามิเตอร์ของประเภท java.io.ObjectOutputStream พารามิเตอร์เป็นอาร์เรย์หากมีการระบุมากกว่าหนึ่งรายการทั้งหมดจะต้องจับคู่ที่จะรายงาน เนื่องจากเรามีกฎเพียงกฎเดียวรายงานชื่อ: Custom-Deserialization-0.html จะถูกสร้างขึ้น
ในกรณีนี้จะต้องมีการกำหนดกฎหนึ่งกฎที่มีสองวิธี ตัวอย่างเดียวกันกว่าในตัวอย่างก่อนหน้านี้สำหรับการ deserialization และอันใหม่เพื่อจับคู่ private void writeObject(ObjectOutputStream out) ดังที่แสดงในโครงสร้าง JSON ด้านบนกฎคุณสมบัติ rile. methods เป็นอาร์เรย์ของวิธีการดังนั้นกฎเช่นนี้สามารถเขียนได้:
{
"rules" : [{
"name" : " Custom serialization and deserialization " ,
"methods" : [{
"name" : " readObject " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectInputStream "
}]
},{
"name" : " writeObject " ,
"report" : " false " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectOutputStream "
}]
}]
}]
} report คุณสมบัติถูกตั้งค่าเป็นเท็จเพื่อหลีกเลี่ยงการรายงานสองครั้งสำหรับกฎเดียวกัน เราใช้วิธีที่สองเช่นเดียวกับเงื่อนไข แต่การรายงานเฉพาะวิธี readObject ควรเพียงพอสำหรับวัตถุประสงค์ของกฎนี้
หากคุณสมบัติไม่ได้กำหนดไว้มันจะตรงกับความจริงเสมอ ตัวอย่างเช่นกฎนี้จะส่งคืนคำจำกัดความทั้งหมด:
{
"rules" : [{
"name" : " Method definitions " ,
"methods" : [{
}]
}]
}นอกจากนี้ยังสามารถพบการเรียกใช้วิธีการ JSON ในกรณีนี้จะเป็น:
{
"rules" : [{
"name" : " String equals " ,
"invocations" : [{
"owner" : " java.lang.String " ,
"method" : {
"name" : " equals "
}
}]
}]
} owner ทรัพย์สินระบุคลาสที่มีวิธีการ
อีกวิธีหนึ่งตัวอย่างการเรียกใช้มีประโยชน์มากกว่าตัวอย่างก่อนหน้านี้:
{
"rules" : [{
"name" : " Method invocation by reflection " ,
"invocations" : [{
"owner" : " java.lang.reflect.Method " ,
"method" : {
"name" : " invoke "
}
}]
}]
} มันเหมือนกันกว่าการเรียกใช้วิธีการใด ๆ แต่ชื่อของวิธีการในกรณีนี้ควรเป็น <init>
{
"rules" : [{
"name" : " String instantiation " ,
"invocations" : [{
"owner" : " java.lang.String " ,
"method" : {
"name" : " <init> "
}
}]
}]
}กฎนี้จะพบเหตุการณ์ที่เกิดขึ้น:
[...]
String s = new String ( "foo" );
[...] ในตัวอย่างนี้เราต้องการค้นหาการใช้งาน deserialization (ไม่ใช่ชั้นเรียนที่กำหนดพฤติกรรมการทำให้เป็นอนุกรมเช่นในตัวอย่างก่อนหน้า) Deserialization เกิดขึ้นเมื่อ ObjectInputStream.readObject() ถูกเรียกใช้ ตัวอย่างเช่นในรหัสตัวอย่างนี้:
ObjectInputStream in = new ObjectInputStream ( fileInputStream );
Object o = in . readObject (); ดังนั้นเราจำเป็นต้องค้นหาการเรียกใช้วิธีการจาก ObjectInputStream ชื่อ readObject แต่มันจะพบข้อดีที่ผิดพลาดจำนวนมากในบริบทการวิจัยเพราะเมื่อชั้นเรียนกำหนด deserialization ที่กำหนดเองพวกเขาทำการเรียกใช้วิธีนี้ภายใน private void readObject(ObjectInputStream in) และนั่นจะทำให้เกิดมลพิษมากเกินไป หากเราต้องการยกเว้นกรณีเหล่านั้นและ notFrom เฉพาะ deserialization ของแท้เท่านั้น
{
"rules" : [{
"name" : " Deserialization usage " ,
"invocations" : [{
"owner" : " java.io.ObjectInputStream " ,
"method" : {
"name" : " readObject "
},
"notFrom" : {
"name" : " readObject " ,
"visibility" : " private "
}
}]
}]
} ไฟล์นี้จะพบ java.io.ObjectInputStream.readObject() การเรียกร้องหากการเรียกร้องไม่ได้ทำภายใน private void readObject(ObjectInputStream in)
คลาสที่รวบรวมด้วยรหัสนี้จะไม่ถูกรายงาน:
private void readObject ( ObjectInputStream in ) throws IOException , ClassNotFoundException {
Object o = in . readObject ();
}แต่อันนี้จะรายงาน:
public Object deserializeObject ( ObjectInputStream in ) throws IOException , ClassNotFoundException {
Object o = in . readObject ();
return o ;
} คุณสมบัติ from สามารถตั้งค่าในการเรียกใช้ในลักษณะเดียวกันมากกว่า notFrom แต่ผลลัพธ์จะเป็นสิ่งที่ตรงกันข้าม: มันจะตรงกันถ้าการเรียกใช้ทำจากวิธีที่กำหนด
superClass คุณสมบัติสามารถใช้ในกรณีนี้ หากเราต้องการค้นหาคลาสทั้งหมดที่ขยาย javax.servlet.http.HttpServlet กฎสามารถ:
{
"rules" : [{
"name" : " Java servlets " ,
"superClass" : " javax.servlet.http.HttpServlet "
}]
}
สามารถเขียนกฎเพื่อค้นหาคลาสที่ใช้อาร์เรย์ของอินเทอร์เฟซ หากมีการกำหนดอินเทอร์เฟซมากกว่าหนึ่งอินเทอร์เฟซในกฎคลาสจะต้องใช้งานทั้งหมดที่จะรายงาน หากเราต้องการค้นหาคลาสที่ใช้ javax.net.ssl.X509TrustManager กฎจะเป็น:
{
"rules" : [{
"name" : " X509TrustManager implementations " ,
"interfaces" : [ " javax.net.ssl.X509TrustManager " ]
}]
} โปรดทราบว่า interfaces เป็น อาร์เรย์ ดังนั้นให้แน่ใจว่าคุณเพิ่มสตริงระหว่างวงเล็บเหลี่ยมเช่น: ["interface1", "interface2", ...]
มีการสนับสนุนคำอธิบายประกอบ คุณสมบัติคำอธิบายประกอบหลายรายการสามารถกำหนดได้ในกฎ (ค้นหาคำอธิบายประกอบชั้นเรียน) ในวิธีการ o ตัวแปร (พารามิเตอร์หรือตัวแปรท้องถิ่น) หากพบทั้งหมดในชั้นเรียนที่วิเคราะห์จะมีการรายงาน ตัวอย่างเช่นหากเราต้องการค้นหาจุดสิ้นสุดของฤดูใบไม้ผลิเราจะค้นหาคลาสหรือวิธีการที่มีคำอธิบายประกอบด้วย org.springframework.web.bind.annotation.RequestMapping ดังนั้นกฎสามารถ:
{
"rules" : [{
"name" : " Spring endpoint - class annotation " ,
"annotations" : [{
"type" : " org.springframework.web.bind.annotation.RequestMapping "
}]
},
{
"name" : " Spring endpoint - method annotation " ,
"methods" : [{
"annotations" : [{
"type" : " org.springframework.web.bind.annotation.RequestMapping "
}]
}]
}]
} rule.fields คุณสมบัติฟิลด์สามารถใช้เพื่อค้นหาฟิลด์คลาส หากเราต้องการค้นหาฟิลด์สตริงส่วนตัวที่มีชื่อรหัสผ่านกฎเช่นนี้สามารถใช้ได้:
{
"rules" : [{
"name" : " Password fields " ,
"fields" : [
{
"visibility" : " private " ,
"type" : " java.lang.String " ,
"nameRegex" : " (password|pass|psswd|passwd) "
}
]
}]
} ในการค้นหา rule.variables สามารถใช้กฎ. variables คุณสมบัตินี้จะรายงานตัวแปรท้องถิ่นและตัวแปรอาร์กิวเมนต์วิธีการ หากเราต้องการค้นหาตัวแปรทั้งหมดของ type javax.servlet.http.Part กฎอาจเป็น:
{
"rules" : [{
"name" : " Servlet upload file " ,
"methods" : [{
"variables" : [{
"type" : " javax.servlet.http.Part "
}]
}]
}]
}สามารถกำหนดกฎหลายข้อในไฟล์ JSON เดียวกัน พวกเขาจะได้รับการประมวลผลและรายงานแยกต่างหากและพวกเขาจะไม่ส่งผลกระทบต่อกันและกัน เราสามารถรวมกฎตัวอย่างก่อนหน้านี้:
{
"rules" : [{
"name" : " Custom deserialization " ,
"methods" : [{
"name" : " readObject " ,
"visibility" : " private " ,
"parameters" : [{
"type" : " java.io.ObjectInputStream "
}]
}]
},{
"name" : " Method invocation by reflection " ,
"invocations" : [{
"owner" : " java.lang.reflect.Method " ,
"method" : {
"name" : " invoke "
}
}]
}]
}ที่นี่เรามีสองกฎ ("กำหนดเอง deserialization" และ "การเรียกใช้วิธีการโดยการสะท้อน") พวกเขาจะได้รับการประมวลผลราวกับว่าคุณทำในการประหารชีวิตสองครั้ง และรายงานต่อกฎจะถูกสร้างขึ้น หากกฎมีชื่อเดียวกันพวกเขาจะถูกรายงานในไฟล์เดียวกัน
โครงการสามารถดาวน์โหลดและสร้างขึ้นเพื่อเพิ่มกฎที่กำหนดเองที่ซับซ้อนมากขึ้นในรหัส Java ที่ไม่ครอบคลุมโดยรูปแบบ JSON มีสามตัวอย่างภายใต้แพ็คเกจ net.nandgr.cba.visitor.checks นั่นคือ CustomDeserializationCheck, DeserializationCheck and InvokeMethodCheck คุณสามารถสร้างกฎของคุณเองได้โดยขยาย net.nandgr.cba.custom.visitor.base.CustomAbstractClassVisitor
ดังที่ได้กล่าวไว้ข้างต้นรายงานถูกสร้างขึ้นโดยค่าเริ่มต้นภายใต้โฟลเดอร์ report ทุกกฎจะมีไฟล์แยกต่างหากเว้นแต่ว่าพวกเขามีชื่อเดียวกัน หากรายงานมีขนาดใหญ่เกินไปคุณสามารถแยกมันโดยใช้พารามิเตอร์ -i,--items-report <maxItems> พารามิเตอร์แต่ละรายการจะถืออาร์กิวเมนต์ที่ระบุหรือน้อยกว่า (ถ้าเป็นครั้งสุดท้าย) ทุกรายการที่รายงานระบุขวดที่พบชื่อคลาสและชื่อวิธี (หากมีความเกี่ยวข้อง) นอกจากนี้ยังแสดงให้เห็นถึงเวอร์ชันที่ถอดรหัสของคลาสเพื่อให้การตรวจสอบด้วยภาพอย่างรวดเร็ว ตัวอย่างของวิธีการแสดงรายการสำหรับกฎเพื่อค้นหา java.io.File Instantiations:

เมื่อค้นหาข้อบกพร่องด้านความปลอดภัยจะมีประโยชน์มากในการมีกราฟการโทร ในขณะนี้ไฟล์ที่ใช้งานร่วมกันได้อย่างง่ายจะถูกสร้างขึ้นภายใต้ไดเรกทอรี report กราฟมีการไหลที่เป็นไปได้ทั้งหมดที่สามารถเรียกใช้ปัญหาที่พบได้ ตัวอย่างเช่นหากมีการใช้กฎเพื่อค้นหา deserialization กราฟที่มีเส้นทางที่เป็นไปได้ทั้งหมดที่นำไปสู่วิธีการที่เรียกว่า deserialization จะถูกสร้างขึ้น
ไฟล์คือ call-graph.dot และมันจะเป็นแบบนี้ (นี่เป็นตัวอย่างที่ง่ายมาก):
graph callGraph {
"demo.callgraph.Class1:method1" -- "demo.callgraph.Class2:method2"
"demo.callgraph.Class3:method3" -- "demo.callgraph.Class2:method2"
}
ในการแสดงด้วยวิธีที่มองเห็นได้ DOT สามารถใช้ (หรือซอฟต์แวร์ที่เข้ากันได้) ตัวอย่างเช่นในการแปลงไฟล์เป็น svg :
dot -Tsvg call-graph.dot -o call-graph.svg
สิ่งนี้จะทำโดยอัตโนมัติโดยค่าเริ่มต้นหากพบ DOT ในเส้นทางระบบ ถ้าไม่สามารถติดตั้ง DOT ในระบบที่ใช้ Debian โดยใช้ sudo apt-get install graphviz
มันจะสร้างไฟล์ SVG ชื่อ call-graph.svg ที่สามารถแปลงเป็น PNG หรือมองเห็นได้โดยใช้โปรแกรมเช่น inkscape หรือเพียงแค่ firefox
ตัวอย่างง่าย ๆ ของไฟล์ call-graph.dot ด้านบนจะเป็น:

มีข้อ จำกัด บางประการเช่นหากรายการที่ค้นหาอยู่ใน java.lang.Runnable.run() หรือวิธีที่คล้ายกันมันจะไม่พบตำแหน่งที่เธรดถูกดำเนินการจาก นอกจากนี้กราฟกำลังทำความสะอาดวัฏจักรเพื่อหลีกเลี่ยง StackOverflowError S มันถูกสร้างขึ้นมาในทางอนุรักษ์นิยมเล็กน้อยดังนั้นหน่วยความจำของระบบจะไม่ถูกระบายออกในระหว่างการวิเคราะห์ไดเรกทอรีขนาดใหญ่
ตัวเลือกเพิ่มเติมจะถูกเพิ่มในเวอร์ชันอนาคต
java -jar cba-cli-<version>.jar -a /path/with/jars -f /path/with/json/file/rules.json
ในการใช้กฎ Java ที่กำหนดเองชื่อคลาสจะต้องระบุเป็นอาร์กิวเมนต์ของ -c
java -jar cba-cli-<version>.jar -a /path/with/jars -c DeserializationCheck
ยอมรับรายการที่คั่นด้วยพื้นที่ดังนั้นจึงสามารถกำหนดกฎที่กำหนดเองได้หลายกฎ (แต่ละกฎจะสร้างรายงานแยกต่างหาก):
java -jar cba-cli-<version>.jar -a /path/with/jars -c DeserializationCheck InvokeMethodCheck CustomDeserializationCheck YourCustomRule
java -jar cba-cli-<version>.jar -a /path/with/jars -f /path/with/json/file/rules.json -c YourCustomRule1 YourCustomRule2
ในการค้นหาข้อผิดพลาดสามารถเพิ่มความย่ำแย่ได้ ระดับการดีบัก:
java -jar cba-cli-<version>.jar -a /path/with/jars -c YourCustomRule1 -v
ระดับการติดตาม:
java -jar cba-cli-<version>.jar -a /path/with/jars -c YourCustomRule1 -vv
ในขณะนี้ APK จะต้องถูกแปลงเป็น jar ก่อนเพื่อวิเคราะห์
d2j-dex2jar.sh -f -o app_to_analyze.jar app_to_analyze.apk-a ไดเรกทอรีที่มีไฟล์ jar ที่แปลงแล้ว มีไฟล์ JAR ที่เรียกใช้งานได้ภายใต้ไดเรกทอรี bin ที่: https://github.com/fergarrui/custom-bytecode-analyzer/blob/master/bin/cba-cli-0.1-snapshot.jar หากคุณต้องการทำการแก้ไขหรือเพิ่มกฎที่กำหนดเองโครงการสามารถสร้างขึ้นได้:
git clone https://github.com/fergarrui/custom-bytecode-analyzer.git
cd custom-bytecode-analyzer
mvn clean package
สองขวดจะถูกสร้างขึ้นภายใต้โฟลเดอร์ target cba-cli-<version>.jar มีการพึ่งพาทั้งหมดและสามารถเรียกใช้งานได้ สามารถรันได้โดยใช้ java -jar cba-cli-<version>.jar