Skip to content

Commit 74c2cfe

Browse files
Lenny HalsethLenny Halseth
authored andcommitted
Use method signatures to align binary and source methods for start info
1 parent ea51f61 commit 74c2cfe

File tree

7 files changed

+545
-114
lines changed

7 files changed

+545
-114
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2018 Secure Decisions, a division of Applied Visions, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* This material is based on research sponsored by the Department of Homeland
17+
* Security (DHS) Science and Technology Directorate, Cyber Security Division
18+
* (DHS S&T/CSD) via contract number HHSP233201600058C.
19+
*/
20+
package com.secdec.codepulse.data.bytecode.parse
21+
22+
/** Base trait describing "Binary Classes" in a codebase.
23+
* A class signature should typically include a name, and type signature where applicable,
24+
* but the actual details are up to the implementing classes.
25+
* The main focus of this base trait is converting class signatures to and from their "memoized" forms.
26+
* Classes stored in the database will have their "memo" in a dedicated column.
27+
*/
28+
sealed trait BinaryClassSignature {
29+
def codebaseType: CodebaseType
30+
def toMemo: BinaryClassSignatureMemo
31+
}
32+
33+
object BinaryClassSignature {
34+
def fromMemo(memo: BinaryClassSignatureMemo): BinaryClassSignature = {
35+
CodebaseMemoParts.fromRaw(memo.raw) getOrElse { unrecognized(memo) } match {
36+
case CodebaseMemoParts(CodebaseType.Java, 1, body) => JavaBinaryClassSignature.parseMemoV1(body)
37+
case _ => unrecognized(memo)
38+
}
39+
}
40+
41+
@inline private def unrecognized(memo: BinaryClassSignatureMemo) = {
42+
throw new IllegalArgumentException(s"Unrecognized binary class signature memo: ${memo.raw}")
43+
}
44+
}
45+
46+
/** "MEMO" representation of a `BinaryClassDeclaration`.
47+
*
48+
* Technically this is a value class wrapper for String, and it exists
49+
* simply for the purpose of providing a type-level hint about what the
50+
* String contains. Clients should not attempt to interact directly with
51+
* the `raw` data. Instead they should call `BinaryClassDeclaration.fromMemo` to
52+
* convert the memo to a nicer in-memory representation.
53+
*/
54+
final case class BinaryClassSignatureMemo(val raw: String) extends AnyVal
55+
56+
// -------------------------------------------------------------
57+
// JAVA
58+
// -------------------------------------------------------------
59+
60+
case class JavaBinaryClassSignature(
61+
access: AccessFlags,
62+
name: ClassName,
63+
signature: JVMClassSignature
64+
) extends BinaryClassSignature {
65+
66+
def codebaseType: CodebaseType = CodebaseType.Java
67+
68+
def toMemo = new BinaryClassSignatureMemo(CodebaseMemoParts.buildRaw(codebaseType, 1, sb => {
69+
sb append access.bits
70+
sb append ';'
71+
sb append name.slashedName
72+
sb append ';'
73+
sb append JVMSignatureConverter.toString(signature)
74+
}))
75+
76+
override def toString = {
77+
val sb = new StringBuilder
78+
sb append access.toStringForClass
79+
if(sb.nonEmpty) sb += ' '
80+
sb append name.dottedName
81+
if(signature.typeParams.nonEmpty) sb append signature.typeParams.mkString("<", ", ", ">")
82+
sb append " extends " append signature.superClass
83+
if(signature.interfaces.nonEmpty) sb append signature.interfaces.mkString(" implements ", ", ", "")
84+
sb.result()
85+
}
86+
}
87+
88+
object JavaBinaryClassSignature {
89+
def parseMemoV1(body: String) = {
90+
// format is "<access>;<slashedName>;<signature>"
91+
// note that signature will usually have ";" in it, so we limit the split to 3 parts
92+
val Array(accessStr, slashedName, rawSignature) = body.split(";", 3)
93+
JavaBinaryClassSignature(
94+
AccessFlags(accessStr.toInt),
95+
ClassName.fromSlashed(slashedName),
96+
JVMSignatureConverter.fromString[JVMClassSignature](rawSignature)
97+
)
98+
}
99+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2018 Secure Decisions, a division of Applied Visions, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* This material is based on research sponsored by the Department of Homeland
17+
* Security (DHS) Science and Technology Directorate, Cyber Security Division
18+
* (DHS S&T/CSD) via contract number HHSP233201600058C.
19+
*/
20+
package com.secdec.codepulse.data.bytecode.parse
21+
22+
sealed trait BinaryMethodSignature extends MethodSignature {
23+
def toMemo: BinaryMethodSignatureMemo
24+
}
25+
object BinaryMethodSignature {
26+
def fromMemo(memo: BinaryMethodSignatureMemo): BinaryMethodSignature = {
27+
CodebaseMemoParts.fromRaw(memo.raw) getOrElse { unrecognized(memo) } match {
28+
case CodebaseMemoParts(CodebaseType.Java, 1, body) => JavaBinaryMethodSignature.parseMemoV1(body)
29+
case _ => unrecognized(memo)
30+
}
31+
}
32+
33+
@inline private def unrecognized(memo: BinaryMethodSignatureMemo): Nothing = {
34+
throw new IllegalArgumentException(s"Unrecognized binary method signature memo: ${memo.raw}")
35+
}
36+
}
37+
38+
/** "MEMO" representation of a `BinaryMethodSignature`.
39+
*
40+
* Technically this is a value class wrapper for String, and it exists
41+
* simply for the purpose of providing a type-level hint about what the
42+
* String contains. Clients should not attempt to interact directly with
43+
* the `raw` data. Instead, they should call `MethodSignature.fromMemo`
44+
* to convert the memo to a nicer in-memory representation.
45+
*
46+
* @param raw
47+
*/
48+
final case class BinaryMethodSignatureMemo(raw: String) extends AnyVal
49+
50+
// -------------------------------------------------------------
51+
// JAVA
52+
// -------------------------------------------------------------
53+
54+
/** Represents a java method signature found via bytecode inspection.
55+
* Method signatures in this form can be converted to and from "memos"
56+
* in order to be stored in the database.
57+
*/
58+
case class JavaBinaryMethodSignature(
59+
access: AccessFlags,
60+
name: String,
61+
typeSignature: JVMMethodTypeSignature
62+
) extends BinaryMethodSignature {
63+
64+
def codebaseType: CodebaseType = CodebaseType.Java
65+
66+
def simplifiedReturnType = SimplifiedType of typeSignature.returnType
67+
def simplifiedArgumentTypes = typeSignature.paramTypes.map(SimplifiedType.of)
68+
69+
def toMemo = new BinaryMethodSignatureMemo(CodebaseMemoParts.buildRaw(codebaseType, 1, sb => {
70+
sb append access.bits
71+
sb append ';'
72+
sb append name
73+
sb append ';'
74+
sb append JVMSignatureConverter.toString(typeSignature)
75+
}))
76+
77+
override def toString = {
78+
val sb = new StringBuilder
79+
sb append access.toStringForMethod
80+
sb += ' '
81+
if(typeSignature.typeParams.nonEmpty) sb append typeSignature.typeParams.mkString("<", ", ", "> ")
82+
sb append typeSignature.returnType
83+
sb += ' '
84+
sb append name
85+
sb append typeSignature.paramTypes.mkString("(", ", ", ")")
86+
if(typeSignature.exceptionTypes.nonEmpty) sb append typeSignature.exceptionTypes.mkString(" throws ", ", ", "")
87+
sb.result()
88+
}
89+
90+
}
91+
92+
object JavaBinaryMethodSignature {
93+
94+
def parseMemoV1(body: String) = {
95+
// format is "<access>;<name>;<signature>"
96+
// note that signature will usually have ";" in it, so we limit the split to 3 parts
97+
val Array(accessStr, name, rawSignature) = body.split(";", 3)
98+
JavaBinaryMethodSignature(
99+
AccessFlags(accessStr.toInt),
100+
name,
101+
JVMSignatureConverter.fromString[JVMMethodTypeSignature](rawSignature)
102+
)
103+
}
104+
105+
}

0 commit comments

Comments
 (0)