Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
Linux Library Inject
Project
Project
Details
Activity
Releases
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
Chu
Linux Library Inject
Commits
897fb1fb
Commit
897fb1fb
authored
Dec 25, 2019
by
Chu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
new process.h, process.cpp
parent
740352d7
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
307 additions
and
99 deletions
+307
-99
CMakeLists.txt
inject/CMakeLists.txt
+1
-1
main.cpp
inject/main.cpp
+1
-1
process.cpp
inject/process.cpp
+89
-82
process.h
inject/process.h
+16
-15
process_old.cpp
inject/process_old.cpp
+166
-0
process_old.h
inject/process_old.h
+34
-0
No files found.
inject/CMakeLists.txt
View file @
897fb1fb
add_executable
(
inject main.cpp
process.cpp process.h elf.cpp elf
.h
)
add_executable
(
inject main.cpp
elf.cpp elf.h process.cpp process
.h
)
set_target_properties
(
inject PROPERTIES LINK_FLAGS
"-static"
)
inject/main.cpp
View file @
897fb1fb
...
...
@@ -3,7 +3,7 @@
#include <vector>
#include "elf.h"
#include "process.h"
#include "process
_old
.h"
void
do_libc_dlopen_mode
();
...
...
inject/process.cpp
View file @
897fb1fb
#include "process.h"
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include "elf.h"
Process
::~
Process
()
{
if
(
attached_
)
detach
();
}
std
::
pair
<
std
::
string
,
std
::
size_t
>
Process
::
find_libc
()
std
::
pair
<
std
::
string
,
void
*
>
Process
::
find_libc
()
{
std
::
string
filename
(
"/proc/"
);
filename
+=
std
::
to_string
(
pid_
);
filename
+=
"/maps"
;
std
::
ifstream
file
(
filename
);
std
::
regex
pattern
(
R"(^([0-9a-h]+)\-.*?(/.*libc\-[0-9\.]*?\.so)$)"
);
std
::
regex
pattern
(
R"(^[0-9a-h]+\-.*?(/.*libc\-[0-9\.]*?\.so)$)"
);
std
::
string
line
;
std
::
smatch
result
;
while
(
std
::
getline
(
file
,
line
))
{
if
(
std
::
regex_search
(
line
,
result
,
pattern
))
return
{
result
[
2
].
str
(),
std
::
stoul
(
result
[
1
].
str
(),
nullptr
,
16
)};
return
{
result
[
1
].
str
(),
reinterpret_cast
<
void
*>
(
std
::
stoul
(
line
,
nullptr
,
16
)
)};
}
throw
std
::
runtime_error
(
"libc.so not found in "
+
filename
);
}
std
::
size_t
Process
::
get_base
()
unsigned
char
*
Process
::
get_rx_area
()
{
std
::
string
filename
(
"/proc/"
);
filename
+=
std
::
to_string
(
pid_
);
filename
+=
"/maps"
;
std
::
ifstream
file
(
filename
);
std
::
string
line
;
file
>>
line
;
return
std
::
stoul
(
line
,
nullptr
,
16
);
while
(
std
::
getline
(
file
,
line
))
{
if
(
line
.
find
(
" r-x"
)
!=
std
::
string
::
npos
)
return
reinterpret_cast
<
unsigned
char
*>
(
std
::
stoul
(
line
,
nullptr
,
16
));
}
throw
std
::
runtime_error
(
"rx area not found in "
+
filename
);
}
std
::
string
Process
::
get_execute
()
unsigned
char
*
Process
::
get_rw_area
()
{
std
::
string
filename
(
"/proc/"
);
filename
+=
std
::
to_string
(
pid_
);
filename
+=
"/exe"
;
char
execute
[
1024
]
=
{
0
};
if
(
readlink
(
filename
.
c_str
(),
execute
,
1023
)
!=
-
1
)
return
execute
;
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
}
std
::
size_t
Process
::
get_entry_point
()
{
Elf
elf
(
get_execute
());
elf
.
set_base
(
get_base
());
return
elf
.
get_entry
();
}
void
Process
::
call_shellcode
(
std
::
vector
<
unsigned
char
>
shellcode
)
{
std
::
cout
<<
"[*] get target process's entry point
\n
"
;
auto
entry_point
=
get_entry_point
();
// replace `ret` with `int3`
if
(
shellcode
[
shellcode
.
size
()
-
1
]
==
0xc3
)
shellcode
[
shellcode
.
size
()
-
1
]
=
0xcc
;
// align
while
(
shellcode
.
size
()
%
sizeof
(
void
*
)
!=
0
)
shellcode
.
emplace_back
(
0x90
);
std
::
cout
<<
"[*] attach to target process
\n
"
;
attach
();
std
::
cout
<<
"[*] backup original code
\n
"
;
auto
original_code
=
read_memory
(
entry_point
,
shellcode
.
size
());
std
::
cout
<<
"[*] backup original registers
\n
"
;
auto
original_registers
=
get_registers
();
std
::
cout
<<
"[*] write shellcode to target process's entry point
\n
"
;
write_memory
(
entry_point
,
shellcode
);
auto
registers
=
original_registers
;
registers
.
rip
=
entry_point
;
std
::
cout
<<
"[*] set %rip to target process's entry point
\n
"
;
set_registers
(
registers
);
std
::
cout
<<
"[*] continue and wait for trap
\n
"
;
continue_and_wait_for_trap
();
std
::
cout
<<
"[*] restore original code
\n
"
;
write_memory
(
entry_point
,
original_code
);
std
::
cout
<<
"[*] restore original registers
\n
"
;
set_registers
(
original_registers
);
std
::
cout
<<
"[*] detach target process
\n
"
;
detach
();
filename
+=
"/maps"
;
std
::
ifstream
file
(
filename
);
std
::
string
line
;
while
(
std
::
getline
(
file
,
line
))
{
if
(
line
.
find
(
" rw"
)
!=
std
::
string
::
npos
)
return
reinterpret_cast
<
unsigned
char
*>
(
std
::
stoul
(
line
,
nullptr
,
16
));
}
throw
std
::
runtime_error
(
"rw area not found in "
+
filename
);
}
void
Process
::
attach
()
...
...
@@ -96,6 +64,7 @@ void Process::attach()
if
(
ptrace
(
PTRACE_ATTACH
,
pid_
,
nullptr
,
nullptr
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
wait
(
nullptr
);
attached_
=
true
;
}
void
Process
::
detach
()
...
...
@@ -103,46 +72,50 @@ void Process::detach()
if
(
ptrace
(
PTRACE_DETACH
,
pid_
,
nullptr
,
nullptr
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
wait
(
nullptr
);
attached_
=
false
;
}
std
::
vector
<
unsigned
char
>
Process
::
read_memory
(
std
::
size_t
address
,
std
::
size_t
size
)
void
Process
::
write
(
unsigned
char
*
address
,
std
::
vector
<
unsigned
char
>
&
data
)
{
std
::
vector
<
unsigned
char
>
data
;
data
.
resize
(
size
);
auto
ptr
=
data
.
data
();
std
::
size_t
n
=
0
;
while
(
n
!=
size
)
check_for_attached
();
auto
data_ptr
=
data
.
data
();
std
::
size_t
total_wrote
=
0
;
while
(
total_wrote
!=
data
.
size
())
{
auto
word
=
ptrace
(
PTRACE_PEEKTEXT
,
pid_
,
address
,
nullptr
);
if
(
word
==
-
1
)
void
*
data_to_write
=
nullptr
;
std
::
memcpy
(
&
data_to_write
,
data_ptr
,
sizeof
(
data_to_write
));
if
(
ptrace
(
PTRACE_POKETEXT
,
pid_
,
address
,
data_to_write
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
auto
to_copy
=
size
-
n
>
sizeof
(
void
*
)
?
sizeof
(
void
*
)
:
size
-
n
;
std
::
memcpy
(
ptr
,
&
word
,
to_copy
);
ptr
+=
to_copy
;
n
+=
to_copy
;
address
+=
sizeof
(
void
*
);
address
+=
sizeof
(
data_to_write
);
data_ptr
+=
sizeof
(
data_to_write
);
total_wrote
+=
sizeof
(
data_to_write
);
}
return
data
;
}
void
Process
::
write_memory
(
std
::
size_t
address
,
std
::
vector
<
unsigned
char
>
data
)
std
::
vector
<
unsigned
char
>
Process
::
read
(
unsigned
char
*
address
,
std
::
size_t
size
)
{
auto
ptr
=
data
.
data
();
std
::
size_t
n
=
0
;
while
(
n
!=
data
.
size
())
check_for_attached
();
std
::
vector
<
unsigned
char
>
data
(
size
%
sizeof
(
void
*
)
==
0
?
size
:
size
+
(
size
-
size
%
sizeof
(
void
*
)));
auto
data_ptr
=
data
.
data
();
std
::
size_t
total_read
=
0
;
while
(
total_read
!=
size
)
{
void
*
to_write
=
nullptr
;
std
::
memcpy
(
&
to_write
,
ptr
,
sizeof
(
to_write
));
if
(
ptrace
(
PTRACE_POKETEXT
,
pid_
,
address
,
to_write
)
==
-
1
)
auto
data_read
=
ptrace
(
PTRACE_PEEKTEXT
,
pid_
,
address
,
nullptr
);
if
(
data_read
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
address
+=
sizeof
(
to_write
);
ptr
+=
sizeof
(
to_write
);
n
+=
sizeof
(
to_write
);
auto
size_to_copy
=
size
-
total_read
>
sizeof
(
data_read
)
?
sizeof
(
data_read
)
:
size
-
total_read
;
std
::
memcpy
(
data_ptr
,
&
data_read
,
size_to_copy
);
address
+=
size_to_copy
;
data_ptr
+=
size_to_copy
;
total_read
+=
size_to_copy
;
}
data
.
resize
(
size
);
return
data
;
}
user_regs_struct
Process
::
get_registers
()
{
check_for_attached
();
user_regs_struct
registers
=
{
0
};
if
(
ptrace
(
PTRACE_GETREGS
,
pid_
,
nullptr
,
&
registers
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
...
...
@@ -151,10 +124,44 @@ user_regs_struct Process::get_registers()
void
Process
::
set_registers
(
const
user_regs_struct
&
registers
)
{
check_for_attached
();
if
(
ptrace
(
PTRACE_SETREGS
,
pid_
,
nullptr
,
&
registers
))
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
}
void
Process
::
call_func
(
void
*
address
,
std
::
array
<
void
*
,
6
>
args
)
{
check_for_attached
();
// 0: 48 bb ef be ad de ef be ad de movabs $0xdeadbeefdeadbeef, %rbx
// a: ff d3 callq *%rbx
// c: cc int3
std
::
vector
<
unsigned
char
>
shellcode
=
{
0x48
,
0xbb
,
0xef
,
0xbe
,
0xad
,
0xde
,
0xef
,
0xbe
,
0xad
,
0xde
,
0xff
,
0xd3
,
0xcc
};
std
::
memcpy
(
shellcode
.
data
()
+
2
,
&
address
,
sizeof
(
address
));
auto
rx_addr
=
get_rx_area
();
auto
original_code
=
read
(
rx_addr
,
shellcode
.
size
());
auto
original_registers
=
get_registers
();
write
(
rx_addr
,
shellcode
);
auto
registers
=
original_registers
;
registers
.
rip
=
reinterpret_cast
<
decltype
(
registers
.
rip
)
>
(
rx_addr
);
registers
.
rdi
=
reinterpret_cast
<
decltype
(
registers
.
rdi
)
>
(
args
[
0
]);
registers
.
rsi
=
reinterpret_cast
<
decltype
(
registers
.
rsi
)
>
(
args
[
1
]);
registers
.
rdx
=
reinterpret_cast
<
decltype
(
registers
.
rdx
)
>
(
args
[
2
]);
registers
.
rcx
=
reinterpret_cast
<
decltype
(
registers
.
rdi
)
>
(
args
[
3
]);
registers
.
r8
=
reinterpret_cast
<
decltype
(
registers
.
rdi
)
>
(
args
[
4
]);
registers
.
r9
=
reinterpret_cast
<
decltype
(
registers
.
rdi
)
>
(
args
[
5
]);
set_registers
(
registers
);
continue_and_wait_for_trap
();
write
(
rx_addr
,
original_code
);
set_registers
(
original_registers
);
}
void
Process
::
check_for_attached
()
{
if
(
!
attached_
)
throw
std
::
runtime_error
(
"process must be attach first"
);
}
void
Process
::
continue_and_wait_for_trap
()
{
if
(
ptrace
(
PTRACE_CONT
,
pid_
,
nullptr
,
nullptr
)
==
-
1
)
...
...
inject/process.h
View file @
897fb1fb
#ifndef LINUX_LIBRARY_INJECT_PROCESS_H
#define LINUX_LIBRARY_INJECT_PROCESS_H
#include <sys/ptrace.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/user.h>
#include <array>
#include <string>
#include <utility>
#include <vector>
class
Process
final
{
public
:
explicit
Process
(
pid_t
pid
)
:
pid_
(
pid
)
{}
std
::
pair
<
std
::
string
,
std
::
size_t
>
find_libc
();
std
::
size_t
get_entry_point
();
void
call_shellcode
(
std
::
vector
<
unsigned
char
>
shellcode
);
private
:
pid_t
pid_
;
std
::
size_t
get_base
();
std
::
string
get_execute
();
explicit
Process
(
pid_t
pid
)
:
pid_
(
pid
),
attached_
(
false
)
{}
~
Process
();
std
::
pair
<
std
::
string
,
void
*>
find_libc
();
unsigned
char
*
get_rx_area
();
unsigned
char
*
get_rw_area
();
void
attach
();
void
detach
();
std
::
vector
<
unsigned
char
>
read_memory
(
std
::
size_t
address
,
std
::
size_t
size
);
void
write_memory
(
std
::
size_t
address
,
std
::
vector
<
unsigned
char
>
data
);
void
write
(
unsigned
char
*
address
,
std
::
vector
<
unsigned
char
>
&
data
);
std
::
vector
<
unsigned
char
>
read
(
unsigned
char
*
address
,
std
::
size_t
size
);
user_regs_struct
get_registers
();
void
set_registers
(
const
user_regs_struct
&
registers
);
void
call_func
(
void
*
address
,
std
::
array
<
void
*
,
6
>
args
);
private
:
pid_t
pid_
;
bool
attached_
;
void
check_for_attached
();
void
continue_and_wait_for_trap
();
};
...
...
inject/process_old.cpp
0 → 100644
View file @
897fb1fb
#include "process_old.h"
#include <sys/wait.h>
#include <unistd.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include "elf.h"
std
::
pair
<
std
::
string
,
std
::
size_t
>
Process
::
find_libc
()
{
std
::
string
filename
(
"/proc/"
);
filename
+=
std
::
to_string
(
pid_
);
filename
+=
"/maps"
;
std
::
ifstream
file
(
filename
);
std
::
regex
pattern
(
R"(^([0-9a-h]+)\-.*?(/.*libc\-[0-9\.]*?\.so)$)"
);
std
::
string
line
;
std
::
smatch
result
;
while
(
std
::
getline
(
file
,
line
))
{
if
(
std
::
regex_search
(
line
,
result
,
pattern
))
return
{
result
[
2
].
str
(),
std
::
stoul
(
result
[
1
].
str
(),
nullptr
,
16
)};
}
throw
std
::
runtime_error
(
"libc.so not found in "
+
filename
);
}
std
::
size_t
Process
::
get_base
()
{
std
::
string
filename
(
"/proc/"
);
filename
+=
std
::
to_string
(
pid_
);
filename
+=
"/maps"
;
std
::
ifstream
file
(
filename
);
std
::
string
line
;
file
>>
line
;
return
std
::
stoul
(
line
,
nullptr
,
16
);
}
std
::
string
Process
::
get_execute
()
{
std
::
string
filename
(
"/proc/"
);
filename
+=
std
::
to_string
(
pid_
);
filename
+=
"/exe"
;
char
execute
[
1024
]
=
{
0
};
if
(
readlink
(
filename
.
c_str
(),
execute
,
1023
)
!=
-
1
)
return
execute
;
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
}
std
::
size_t
Process
::
get_entry_point
()
{
Elf
elf
(
get_execute
());
elf
.
set_base
(
get_base
());
return
elf
.
get_entry
();
}
void
Process
::
call_shellcode
(
std
::
vector
<
unsigned
char
>
shellcode
)
{
std
::
cout
<<
"[*] get target process's entry point
\n
"
;
auto
entry_point
=
get_entry_point
();
// replace `ret` with `int3`
if
(
shellcode
[
shellcode
.
size
()
-
1
]
==
0xc3
)
shellcode
[
shellcode
.
size
()
-
1
]
=
0xcc
;
// align
while
(
shellcode
.
size
()
%
sizeof
(
void
*
)
!=
0
)
shellcode
.
emplace_back
(
0x90
);
std
::
cout
<<
"[*] attach to target process
\n
"
;
attach
();
std
::
cout
<<
"[*] backup original code
\n
"
;
auto
original_code
=
read_memory
(
entry_point
,
shellcode
.
size
());
std
::
cout
<<
"[*] backup original registers
\n
"
;
auto
original_registers
=
get_registers
();
std
::
cout
<<
"[*] write shellcode to target process's entry point
\n
"
;
write_memory
(
entry_point
,
shellcode
);
auto
registers
=
original_registers
;
registers
.
rip
=
entry_point
;
std
::
cout
<<
"[*] set %rip to target process's entry point
\n
"
;
set_registers
(
registers
);
std
::
cout
<<
"[*] continue and wait for trap
\n
"
;
continue_and_wait_for_trap
();
std
::
cout
<<
"[*] restore original code
\n
"
;
write_memory
(
entry_point
,
original_code
);
std
::
cout
<<
"[*] restore original registers
\n
"
;
set_registers
(
original_registers
);
std
::
cout
<<
"[*] detach target process
\n
"
;
detach
();
}
void
Process
::
attach
()
{
if
(
ptrace
(
PTRACE_ATTACH
,
pid_
,
nullptr
,
nullptr
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
wait
(
nullptr
);
}
void
Process
::
detach
()
{
if
(
ptrace
(
PTRACE_DETACH
,
pid_
,
nullptr
,
nullptr
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
wait
(
nullptr
);
}
std
::
vector
<
unsigned
char
>
Process
::
read_memory
(
std
::
size_t
address
,
std
::
size_t
size
)
{
std
::
vector
<
unsigned
char
>
data
;
data
.
resize
(
size
);
auto
ptr
=
data
.
data
();
std
::
size_t
n
=
0
;
while
(
n
!=
size
)
{
auto
word
=
ptrace
(
PTRACE_PEEKTEXT
,
pid_
,
address
,
nullptr
);
if
(
word
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
auto
to_copy
=
size
-
n
>
sizeof
(
void
*
)
?
sizeof
(
void
*
)
:
size
-
n
;
std
::
memcpy
(
ptr
,
&
word
,
to_copy
);
ptr
+=
to_copy
;
n
+=
to_copy
;
address
+=
sizeof
(
void
*
);
}
return
data
;
}
void
Process
::
write_memory
(
std
::
size_t
address
,
std
::
vector
<
unsigned
char
>
data
)
{
auto
ptr
=
data
.
data
();
std
::
size_t
n
=
0
;
while
(
n
!=
data
.
size
())
{
void
*
to_write
=
nullptr
;
std
::
memcpy
(
&
to_write
,
ptr
,
sizeof
(
to_write
));
if
(
ptrace
(
PTRACE_POKETEXT
,
pid_
,
address
,
to_write
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
address
+=
sizeof
(
to_write
);
ptr
+=
sizeof
(
to_write
);
n
+=
sizeof
(
to_write
);
}
}
user_regs_struct
Process
::
get_registers
()
{
user_regs_struct
registers
=
{
0
};
if
(
ptrace
(
PTRACE_GETREGS
,
pid_
,
nullptr
,
&
registers
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
return
registers
;
}
void
Process
::
set_registers
(
const
user_regs_struct
&
registers
)
{
if
(
ptrace
(
PTRACE_SETREGS
,
pid_
,
nullptr
,
&
registers
))
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
}
void
Process
::
continue_and_wait_for_trap
()
{
if
(
ptrace
(
PTRACE_CONT
,
pid_
,
nullptr
,
nullptr
)
==
-
1
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
int
status
;
wait
(
&
status
);
if
(
WSTOPSIG
(
status
)
!=
SIGTRAP
)
throw
std
::
runtime_error
(
std
::
strerror
(
errno
));
}
inject/process_old.h
0 → 100644
View file @
897fb1fb
#ifndef LINUX_LIBRARY_INJECT_PROCESS_OLD_H
#define LINUX_LIBRARY_INJECT_PROCESS_OLD_H
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <string>
#include <utility>
#include <vector>
class
Process
final
{
public
:
explicit
Process
(
pid_t
pid
)
:
pid_
(
pid
)
{}
std
::
pair
<
std
::
string
,
std
::
size_t
>
find_libc
();
std
::
size_t
get_entry_point
();
void
call_shellcode
(
std
::
vector
<
unsigned
char
>
shellcode
);
private
:
pid_t
pid_
;
std
::
size_t
get_base
();
std
::
string
get_execute
();
void
attach
();
void
detach
();
std
::
vector
<
unsigned
char
>
read_memory
(
std
::
size_t
address
,
std
::
size_t
size
);
void
write_memory
(
std
::
size_t
address
,
std
::
vector
<
unsigned
char
>
data
);
user_regs_struct
get_registers
();
void
set_registers
(
const
user_regs_struct
&
registers
);
void
continue_and_wait_for_trap
();
};
#endif // LINUX_LIBRARY_INJECT_PROCESS_OLD_H
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