Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
cwe_checker
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
fact-depend
cwe_checker
Commits
954f1447
Commit
954f1447
authored
Oct 22, 2020
by
Enkelmann
Committed by
Enkelmann
Nov 03, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use registers parsed from Ghidra on the Rust side.
parent
45ececd2
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
115 additions
and
79 deletions
+115
-79
Makefile
Makefile
+0
-1
mod.rs
cwe_checker_rs/src/analysis/pointer_inference/context/mod.rs
+2
-1
tests.rs
...hecker_rs/src/analysis/pointer_inference/context/tests.rs
+14
-9
trait_impls.rs
..._rs/src/analysis/pointer_inference/context/trait_impls.rs
+20
-19
term.rs
cwe_checker_rs/src/intermediate_representation/term.rs
+30
-8
term.rs
cwe_checker_rs/src/pcode/term.rs
+38
-6
mod.rs
cwe_checker_rs/src/term/mod.rs
+9
-2
mod.rs
cwe_checker_rs/src/utils/mod.rs
+0
-31
ParseCspecContent.java
ghidra/p_code_extractor/internal/ParseCspecContent.java
+0
-1
serde_json.ml
src/utils/serde_json.ml
+2
-1
No files found.
Makefile
View file @
954f1447
...
...
@@ -4,7 +4,6 @@ GHIDRA_PATH =
all
:
cargo build
--release
mkdir
-p
${
HOME
}
/.config/cwe_checker
cp src/utils/registers.json
${
HOME
}
/.config/cwe_checker/registers.json
cp src/config.json
${
HOME
}
/.config/cwe_checker/config.json
ifdef
GHIDRA_PATH
cargo
install
--path
caller
--locked
...
...
cwe_checker_rs/src/analysis/pointer_inference/context/mod.rs
View file @
954f1447
...
...
@@ -291,12 +291,13 @@ impl<'a> Context<'a> {
new_state
.clear_stack_parameter
(
extern_symbol
,
&
self
.project.stack_pointer_register
),
Some
(
&
call
.tid
),
);
let
calling_conv
=
extern_symbol
.get_calling_convention
(
&
self
.project
);
let
mut
possible_referenced_ids
=
BTreeSet
::
new
();
if
extern_symbol
.parameters
.is_empty
()
&&
extern_symbol
.return_values
.is_empty
()
{
// We assume here that we do not know the parameters and approximate them by all possible parameter registers.
// This approximation is wrong if the function is known but has neither parameters nor return values.
// We cannot distinguish these two cases yet.
for
parameter_register_name
in
self
.project.parameter_registers
.iter
()
{
for
parameter_register_name
in
calling_conv
.parameter_register
.iter
()
{
if
let
Some
(
register_value
)
=
state
.get_register_by_name
(
parameter_register_name
)
{
possible_referenced_ids
.append
(
&
mut
register_value
.referenced_ids
());
}
...
...
cwe_checker_rs/src/analysis/pointer_inference/context/tests.rs
View file @
954f1447
...
...
@@ -12,7 +12,7 @@ fn new_id(time: &str, reg_name: &str) -> AbstractIdentifier {
}
fn
mock_extern_symbol
(
name
:
&
str
)
->
ExternSymbol
{
let
arg
=
Arg
::
Register
(
register
(
"R
A
X"
));
let
arg
=
Arg
::
Register
(
register
(
"R
D
X"
));
ExternSymbol
{
tid
:
Tid
::
new
(
"extern_"
.to_string
()
+
name
),
name
:
name
.into
(),
...
...
@@ -80,13 +80,18 @@ fn mock_project() -> (Project, Config) {
tid
:
Tid
::
new
(
"program"
),
term
:
program
,
};
let
cconv
=
CallingConvention
{
name
:
"default"
.to_string
(),
parameter_register
:
vec!
[
"RDX"
.to_string
()],
return_register
:
vec!
[
"RDX"
.to_string
()],
callee_saved_register
:
vec!
[
"callee_saved_reg"
.to_string
()],
};
(
Project
{
program
:
program_term
,
cpu_architecture
:
"x86_64"
.to_string
(),
stack_pointer_register
:
register
(
"RSP"
),
callee_saved_registers
:
vec!
[
"callee_saved_reg"
.to_string
()],
parameter_registers
:
vec!
[
"RAX"
.to_string
()],
calling_conventions
:
vec!
[
cconv
],
},
Config
{
allocation_symbols
:
vec!
[
"malloc"
.into
()],
...
...
@@ -186,9 +191,9 @@ fn context_problem_implementation() {
let
malloc
=
call_term
(
"extern_malloc"
);
let
mut
state_after_malloc
=
context
.update_call_stub
(
&
state
,
&
malloc
)
.unwrap
();
assert_eq!
(
state_after_malloc
.get_register
(
&
register
(
"R
A
X"
))
.unwrap
(),
state_after_malloc
.get_register
(
&
register
(
"R
D
X"
))
.unwrap
(),
Data
::
Pointer
(
PointerDomain
::
new
(
new_id
(
"call_extern_malloc"
,
"R
A
X"
),
new_id
(
"call_extern_malloc"
,
"R
D
X"
),
bv
(
0
)
))
);
...
...
@@ -214,7 +219,7 @@ fn context_problem_implementation() {
state_after_malloc
.set_register
(
&
register
(
"callee_saved_reg"
),
Data
::
Pointer
(
PointerDomain
::
new
(
new_id
(
"call_extern_malloc"
,
"R
A
X"
),
new_id
(
"call_extern_malloc"
,
"R
D
X"
),
bv
(
0
),
)),
);
...
...
@@ -223,7 +228,7 @@ fn context_problem_implementation() {
.update_call_stub
(
&
state_after_malloc
,
&
free
)
.unwrap
();
assert
!
(
state_after_free
.get_register
(
&
register
(
"R
A
X"
))
.get_register
(
&
register
(
"R
D
X"
))
.unwrap
()
.is_top
());
assert_eq!
(
state_after_free
.memory
.get_num_objects
(),
2
);
...
...
@@ -232,7 +237,7 @@ fn context_problem_implementation() {
.get_register
(
&
register
(
"callee_saved_reg"
))
.unwrap
(),
Data
::
Pointer
(
PointerDomain
::
new
(
new_id
(
"call_extern_malloc"
,
"R
A
X"
),
new_id
(
"call_extern_malloc"
,
"R
D
X"
),
bv
(
0
)
))
);
...
...
@@ -304,7 +309,7 @@ fn update_return() {
.ids_known_to_caller
.insert
(
other_callsite_id
.clone
());
state_before_return
.set_register
(
&
register
(
"R
A
X"
),
&
register
(
"R
D
X"
),
Data
::
Pointer
(
PointerDomain
::
new
(
new_id
(
"call_callee_other"
,
"RSP"
),
bv
(
-
32
),
...
...
cwe_checker_rs/src/analysis/pointer_inference/context/trait_impls.rs
View file @
954f1447
...
...
@@ -209,26 +209,27 @@ impl<'a> crate::analysis::interprocedural_fixpoint::Context<'a> for Context<'a>
Jmp
::
CallInd
{
..
}
=>
panic!
(
"Indirect calls to extern symbols not yet supported."
),
_
=>
panic!
(
"Malformed control flow graph encountered."
),
};
// Clear non-callee-saved registers from the state.
new_state
.clear_non_callee_saved_register
(
&
self
.project.callee_saved_registers
[
..
]);
// On x86, remove the return address from the stack (other architectures pass the return address in a register, not on the stack).
// Note that in some calling conventions the callee also clears function parameters from the stack.
// We do not detect and handle these cases yet.
let
stack_register
=
&
self
.project.stack_pointer_register
;
let
stack_pointer
=
state
.get_register
(
stack_register
)
.unwrap
();
match
self
.project.cpu_architecture
.as_str
()
{
"x86"
|
"x86_64"
=>
{
let
offset
=
Bitvector
::
from_u64
(
stack_register
.size
.into
())
.into_truncate
(
apint
::
BitWidth
::
from
(
stack_register
.size
))
.unwrap
();
new_state
.set_register
(
stack_register
,
stack_pointer
.bin_op
(
BinOpType
::
IntAdd
,
&
offset
.into
()),
);
}
_
=>
new_state
.set_register
(
stack_register
,
stack_pointer
),
}
if
let
Some
(
extern_symbol
)
=
self
.extern_symbol_map
.get
(
call_target
)
{
// Clear non-callee-saved registers from the state.
let
cconv
=
extern_symbol
.get_calling_convention
(
&
self
.project
);
new_state
.clear_non_callee_saved_register
(
&
cconv
.callee_saved_register
[
..
]);
// On x86, remove the return address from the stack (other architectures pass the return address in a register, not on the stack).
// Note that in some calling conventions the callee also clears function parameters from the stack.
// We do not detect and handle these cases yet.
let
stack_register
=
&
self
.project.stack_pointer_register
;
let
stack_pointer
=
state
.get_register
(
stack_register
)
.unwrap
();
match
self
.project.cpu_architecture
.as_str
()
{
"x86"
|
"x86_64"
=>
{
let
offset
=
Bitvector
::
from_u64
(
stack_register
.size
.into
())
.into_truncate
(
apint
::
BitWidth
::
from
(
stack_register
.size
))
.unwrap
();
new_state
.set_register
(
stack_register
,
stack_pointer
.bin_op
(
BinOpType
::
IntAdd
,
&
offset
.into
()),
);
}
_
=>
new_state
.set_register
(
stack_register
,
stack_pointer
),
}
// Check parameter for possible use-after-frees
self
.check_parameter_register_for_dangling_pointer
(
state
,
call
,
extern_symbol
);
...
...
cwe_checker_rs/src/intermediate_representation/term.rs
View file @
954f1447
...
...
@@ -203,6 +203,19 @@ impl ExternSymbol {
Err
(
anyhow!
(
"Wrong number of parameter values"
))
}
}
/// Get the calling convention corresponding to the extern symbol.
pub
fn
get_calling_convention
<
'a
>
(
&
self
,
project
:
&
'a
Project
)
->
&
'a
CallingConvention
{
let
cconv_name
=
match
self
.calling_convention
{
Some
(
ref
name
)
=>
name
,
None
=>
"default"
,
};
project
.calling_conventions
.iter
()
.find
(|
cconv
|
cconv
.name
==
cconv_name
)
.unwrap
()
}
}
/// The `Program` structure represents a disassembled binary.
...
...
@@ -230,6 +243,21 @@ impl Program {
}
}
/// Calling convention related data
#[derive(Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
Hash,
Clone)]
pub
struct
CallingConvention
{
/// The name of the calling convention
#[serde(rename
=
"calling_convention"
)]
pub
name
:
String
,
/// A list of possible parameter register
pub
parameter_register
:
Vec
<
String
>
,
/// A list of possible return register
pub
return_register
:
Vec
<
String
>
,
/// A list of callee-saved register,
/// i.e. the values of these registers should be the same after the call as they were before the call.
pub
callee_saved_register
:
Vec
<
String
>
,
}
/// The `Project` struct is the main data structure representing a binary.
///
/// It contains information about the disassembled binary
...
...
@@ -242,14 +270,8 @@ pub struct Project {
pub
cpu_architecture
:
String
,
/// The stack pointer register for the given CPU architecture.
pub
stack_pointer_register
:
Variable
,
/// The names of callee-saved registers for the standard calling convention
/// for the given CPU architecture.
/// Note that this field may be removed in the future.
pub
callee_saved_registers
:
Vec
<
String
>
,
/// The names of parameter registers for the standard calling convention
/// for the given CPU architecture.
/// Note that this field may be removed in the future.
pub
parameter_registers
:
Vec
<
String
>
,
/// The known calling conventions that may be used for calls to extern functions.
pub
calling_conventions
:
Vec
<
CallingConvention
>
,
}
impl
Project
{
...
...
cwe_checker_rs/src/pcode/term.rs
View file @
954f1447
...
...
@@ -2,6 +2,7 @@ use super::{Expression, ExpressionType, Variable};
use
crate
::
intermediate_representation
::
Arg
as
IrArg
;
use
crate
::
intermediate_representation
::
Blk
as
IrBlk
;
use
crate
::
intermediate_representation
::
ByteSize
;
use
crate
::
intermediate_representation
::
CallingConvention
as
IrCallingConvention
;
use
crate
::
intermediate_representation
::
Def
as
IrDef
;
use
crate
::
intermediate_representation
::
Expression
as
IrExpression
;
use
crate
::
intermediate_representation
::
ExternSymbol
as
IrExternSymbol
;
...
...
@@ -387,10 +388,32 @@ impl From<Program> for IrProgram {
}
#[derive(Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
Hash,
Clone)]
pub
struct
CallingConvention
{
#[serde(rename
=
"calling_convention"
)]
pub
name
:
String
,
parameter_register
:
Vec
<
String
>
,
return_register
:
Vec
<
String
>
,
unaffected_register
:
Vec
<
String
>
,
killed_by_call_register
:
Vec
<
String
>
,
}
impl
From
<
CallingConvention
>
for
IrCallingConvention
{
fn
from
(
cconv
:
CallingConvention
)
->
IrCallingConvention
{
IrCallingConvention
{
name
:
cconv
.name
,
parameter_register
:
cconv
.parameter_register
,
return_register
:
cconv
.return_register
,
callee_saved_register
:
cconv
.unaffected_register
,
}
}
}
#[derive(Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
Hash,
Clone)]
pub
struct
Project
{
pub
program
:
Term
<
Program
>
,
pub
cpu_architecture
:
String
,
pub
stack_pointer_register
:
Variable
,
pub
register_calling_convention
:
Vec
<
CallingConvention
>
,
}
impl
From
<
Project
>
for
IrProject
{
...
...
@@ -400,15 +423,15 @@ impl From<Project> for IrProject {
tid
:
project
.program.tid
,
term
:
project
.program.term
.into
(),
};
let
(
params
,
callee_saved
)
=
crate
::
utils
::
get_generic_parameter_and_callee_saved_register
(
&
project
.cpu_architecture
,
);
IrProject
{
program
,
cpu_architecture
:
project
.cpu_architecture
,
stack_pointer_register
:
project
.stack_pointer_register
.into
(),
callee_saved_registers
:
callee_saved
,
parameter_registers
:
params
,
calling_conventions
:
project
.register_calling_convention
.into_iter
()
.map
(|
cconv
|
cconv
.into
())
.collect
(),
}
}
}
...
...
@@ -691,7 +714,16 @@ mod tests {
"
size
": 8,
"
is_virtual
": false
},
"
cpu_architecture
": "
x86_64
"
"
cpu_architecture
": "
x86_64
",
"
register_calling_convention
": [
{
"
calling_convention
": "
default
",
"
parameter_register
": [],
"
return_register
": [],
"
unaffected_register
": [],
"
killed_by_call_register
": []
}
]
}
"
#
,
)
...
...
cwe_checker_rs/src/term/mod.rs
View file @
954f1447
use
crate
::
bil
::
*
;
use
crate
::
intermediate_representation
::
Arg
as
IrArg
;
use
crate
::
intermediate_representation
::
Blk
as
IrBlk
;
use
crate
::
intermediate_representation
::
CallingConvention
as
IrCallingConvention
;
use
crate
::
intermediate_representation
::
Def
as
IrDef
;
use
crate
::
intermediate_representation
::
Expression
as
IrExpression
;
use
crate
::
intermediate_representation
::
Jmp
as
IrJmp
;
...
...
@@ -308,6 +309,7 @@ pub struct Project {
pub
stack_pointer_register
:
Variable
,
pub
callee_saved_registers
:
Vec
<
String
>
,
pub
parameter_registers
:
Vec
<
String
>
,
pub
return_registers
:
Vec
<
String
>
,
}
impl
Project
{
...
...
@@ -354,12 +356,17 @@ impl From<Project> for IrProject {
tid
:
project
.program.tid
,
term
:
project
.program.term
.into
(),
};
let
default_cconv
=
IrCallingConvention
{
name
:
"default"
.to_string
(),
parameter_register
:
project
.parameter_registers
,
return_register
:
project
.return_registers
,
callee_saved_register
:
project
.callee_saved_registers
,
};
IrProject
{
program
,
cpu_architecture
:
project
.cpu_architecture
,
stack_pointer_register
:
project
.stack_pointer_register
.into
(),
callee_saved_registers
:
project
.callee_saved_registers
,
parameter_registers
:
project
.parameter_registers
,
calling_conventions
:
vec!
[
default_cconv
],
}
}
}
...
...
cwe_checker_rs/src/utils/mod.rs
View file @
954f1447
pub
mod
log
;
/// Get the names of parameter registers and callee saved registers
/// of the standard calling convention for the given architecture.
///
/// The registers are read from a configuration file.
pub
fn
get_generic_parameter_and_callee_saved_register
(
cpu_architecture
:
&
str
,
)
->
(
Vec
<
String
>
,
Vec
<
String
>
)
{
let
project_dirs
=
directories
::
ProjectDirs
::
from
(
""
,
""
,
"cwe_checker"
)
.expect
(
"Could not discern location of configuration files."
);
let
config_dir
=
project_dirs
.config_dir
();
let
register_config_path
=
config_dir
.join
(
"registers.json"
);
let
file
=
std
::
fs
::
read_to_string
(
register_config_path
)
.expect
(
"Could not read register configuration file"
);
let
mut
registers_json
:
serde_json
::
Value
=
serde_json
::
from_str
(
&
file
)
.unwrap
();
match
cpu_architecture
{
"x86"
|
"x86_32"
=>
registers_json
=
registers_json
[
"elf"
][
"x86"
][
"cdecl"
]
.clone
(),
"ARM_32"
=>
registers_json
=
registers_json
[
"elf"
][
"armv7"
]
.clone
(),
_
=>
registers_json
=
registers_json
[
"elf"
][
cpu_architecture
]
.clone
(),
}
let
mut
callee_saved
:
Vec
<
String
>
=
serde_json
::
from_value
(
registers_json
[
"callee_saved"
]
.clone
())
.unwrap
();
let
mut
callee_saved_float
:
Vec
<
String
>
=
serde_json
::
from_value
(
registers_json
[
"float_callee_saved"
]
.clone
())
.unwrap
();
callee_saved
.append
(
&
mut
callee_saved_float
);
let
mut
params
:
Vec
<
String
>
=
serde_json
::
from_value
(
registers_json
[
"params"
]
.clone
())
.unwrap
();
let
mut
params_float
:
Vec
<
String
>
=
serde_json
::
from_value
(
registers_json
[
"float_params"
]
.clone
())
.unwrap
();
params
.append
(
&
mut
params_float
);
(
params
,
callee_saved
)
}
/// Get the contents of a configuration file.
pub
fn
read_config_file
(
filename
:
&
str
)
->
serde_json
::
Value
{
let
project_dirs
=
directories
::
ProjectDirs
::
from
(
""
,
""
,
"cwe_checker"
)
...
...
ghidra/p_code_extractor/internal/ParseCspecContent.java
View file @
954f1447
...
...
@@ -190,7 +190,6 @@ public class ParseCspecContent {
XmlElement
languageEnter
=
parser
.
peek
();
if
(
languageEnter
.
getAttribute
(
"id"
).
equals
(
languageId
.
getIdAsString
()))
{
cspecName
=
getCompilerName
(
parser
);
break
;
}
else
{
discardSubTree
(
parser
);
}
...
...
src/utils/serde_json.ml
View file @
954f1447
...
...
@@ -308,5 +308,6 @@ let of_project (project: Project.t) (extern_symbols: extern_symbol List.t) (entr
(
"cpu_architecture"
,
build_string
(
Arch
.
to_string
(
Project
.
arch
project
)));
(
"stack_pointer_register"
,
of_var
(
Symbol_utils
.
stack_register
project
));
(
"callee_saved_registers"
,
build_array
(
List
.
map
(
Cconv
.
get_register_list
project
"callee_saved"
)
~
f
:
(
fun
reg_name
->
build_string
reg_name
)
));
(
"parameter_registers"
,
build_array
(
List
.
map
(
Cconv
.
get_register_list
project
"params"
)
~
f
:
(
fun
reg_name
->
build_string
reg_name
)
))
(
"parameter_registers"
,
build_array
(
List
.
map
(
Cconv
.
get_register_list
project
"params"
)
~
f
:
(
fun
reg_name
->
build_string
reg_name
)
));
(
"return_registers"
,
build_array
(
List
.
map
(
Cconv
.
get_register_list
project
"return"
)
~
f
:
(
fun
reg_name
->
build_string
reg_name
)
))
]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment