Sie können verwenden https://godbolt.org/ Es gibt ein paar Dinge, die Sie tun können, um die Montage zu erschweren. Erstens kann man die Symbole ausblenden (also checkSecret()
ist nicht so offensichtlich), und die zweite, eine Funktion zu verwenden, um den Schlüssel/das Kennwort zu generieren. Der Gedanke dahinter ist, dass es länger dauert, den Teil des Codes zu finden, der zur Umgehung der Sicherheit führt, so dass auch kein Aufruf aus der main
Funktion ist wahrscheinlich eine gute Idee.
Wir betrachten zwei Ansätze:
- ein ausdrücklich angegebenes Passwort
- eine Funktion, die das Passwort generiert
Hier ist ein Beispiel für die erste:
#include <string>
#include <iostream>
using namespace std;
string secretKey = "fdasfdasfydsafhidljj3r32R#@f";
bool securityCheck(string key){
if(key==secretKey) cout << "Success!" << endl;
return key==secretKey;
}
int main(){
securityCheck(secretKey);
}
Wie Sie auf der folgenden Seite noch deutlicher sehen können https://godbolt.org/ erzeugt dies die folgende Baugruppe (mit gcc 11.2):
secretKey[abi:cxx11]:
.zero 32
.LC0:
.string "Success!"
securityCheck(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
test al, al
je .L16
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
.L16:
mov rax, QWORD PTR [rbp-8]
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
leave
ret
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 40
lea rax, [rbp-48]
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [complete object constructor]
lea rax, [rbp-48]
mov rdi, rax
call securityCheck(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
lea rax, [rbp-48]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
mov eax, 0
jmp .L22
mov rbx, rax
lea rax, [rbp-48]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
mov rax, rbx
mov rdi, rax
call _Unwind_Resume
.L22:
mov rbx, QWORD PTR [rbp-8]
leave
ret
.LC1:
.string "basic_string::_M_construct null not valid"
.LC2:
.string "fdasfdasfydsafhidljj3r32R#@f"
__static_initialization_and_destruction_0(int, int):
push rbp
mov rbp, rsp
push rbx
sub rsp, 40
mov DWORD PTR [rbp-36], edi
mov DWORD PTR [rbp-40], esi
cmp DWORD PTR [rbp-36], 1
jne .L58
cmp DWORD PTR [rbp-40], 65535
jne .L58
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
call __cxa_atexit
lea rax, [rbp-17]
mov rdi, rax
call std::allocator<char>::allocator() [complete object constructor]
lea rax, [rbp-17]
mov rdx, rax
mov esi, OFFSET FLAT:.LC2
mov edi, OFFSET FLAT:secretKey[abi:cxx11]
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&)
lea rax, [rbp-17]
mov rdi, rax
call std::allocator<char>::~allocator() [complete object destructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov edi, OFFSET FLAT:std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
call __cxa_atexit
jmp .L58
mov rbx, rax
lea rax, [rbp-17]
mov rdi, rax
call std::allocator<char>::~allocator() [complete object destructor]
mov rax, rbx
mov rdi, rax
call _Unwind_Resume
.L58:
mov rbx, QWORD PTR [rbp-8]
leave
ret
_GLOBAL__sub_I_secretKey[abi:cxx11]:
push rbp
mov rbp, rsp
mov esi, 65535
mov edi, 1
call __static_initialization_and_destruction_0(int, int)
pop rbp
ret
Sie können sehen, dass die secretKey
ist deutlich sichtbar, und die Funktionsnamen sind es auch.
Hier ist ein zweites Beispiel:
#include <string>
#include <iostream>
using namespace std;
string getSecretKey(){
srand(100);
string chars = "qwertyuioplkjhgfdsazxcvbnm123456789";
string result = "";
for(int i = 0; i < 100; ++i){
result += chars[rand()%chars.size()];
}
return result;
}
string secretKey = getSecretKey();
bool securityCheck(string key){
if(key==secretKey) cout << "Success!" << endl;
return key==secretKey;
}
int main(){
securityCheck(secretKey);
}
Das Ergebnis ist die folgende Baugruppe:
.LC0:
.string "qwertyuioplkjhgfdsazxcvbnm123456789"
.LC1:
.string ""
getSecretKey[abi:cxx11]():
push rbp
mov rbp, rsp
push rbx
sub rsp, 72
mov QWORD PTR [rbp-72], rdi
mov edi, 100
call srand
lea rax, [rbp-22]
mov rdi, rax
call std::allocator<char>::allocator() [complete object constructor]
lea rdx, [rbp-22]
lea rax, [rbp-64]
mov esi, OFFSET FLAT:.LC0
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&)
lea rax, [rbp-22]
mov rdi, rax
call std::allocator<char>::~allocator() [complete object destructor]
lea rax, [rbp-21]
mov rdi, rax
call std::allocator<char>::allocator() [complete object constructor]
lea rdx, [rbp-21]
mov rax, QWORD PTR [rbp-72]
mov esi, OFFSET FLAT:.LC1
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&)
lea rax, [rbp-21]
mov rdi, rax
call std::allocator<char>::~allocator() [complete object destructor]
mov DWORD PTR [rbp-20], 0
jmp .L16
.L17:
call rand
movsx rbx, eax
lea rax, [rbp-64]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const
mov rcx, rax
mov rax, rbx
mov edx, 0
div rcx
mov rcx, rdx
mov rdx, rcx
lea rax, [rbp-64]
mov rsi, rdx
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator[](unsigned long)
movzx eax, BYTE PTR [rax]
movsx edx, al
mov rax, QWORD PTR [rbp-72]
mov esi, edx
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator+=(char)
add DWORD PTR [rbp-20], 1
.L16:
cmp DWORD PTR [rbp-20], 99
jle .L17
nop
lea rax, [rbp-64]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
jmp .L26
mov rbx, rax
lea rax, [rbp-22]
mov rdi, rax
call std::allocator<char>::~allocator() [complete object destructor]
mov rax, rbx
mov rdi, rax
call _Unwind_Resume
mov rbx, rax
lea rax, [rbp-21]
mov rdi, rax
call std::allocator<char>::~allocator() [complete object destructor]
jmp .L21
mov rbx, rax
mov rax, QWORD PTR [rbp-72]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
.L21:
lea rax, [rbp-64]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
mov rax, rbx
mov rdi, rax
call _Unwind_Resume
.L26:
mov rax, QWORD PTR [rbp-72]
mov rbx, QWORD PTR [rbp-8]
leave
ret
secretKey[abi:cxx11]:
.zero 32
.LC2:
.string "Success!"
securityCheck(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
test al, al
je .L28
mov esi, OFFSET FLAT:.LC2
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
.L28:
mov rax, QWORD PTR [rbp-8]
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
leave
ret
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 40
lea rax, [rbp-48]
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [complete object constructor]
lea rax, [rbp-48]
mov rdi, rax
call securityCheck(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
lea rax, [rbp-48]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
mov eax, 0
jmp .L34
mov rbx, rax
lea rax, [rbp-48]
mov rdi, rax
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
mov rax, rbx
mov rdi, rax
call _Unwind_Resume
.L34:
mov rbx, QWORD PTR [rbp-8]
leave
ret
.LC3:
.string "basic_string::_M_construct null not valid"
__static_initialization_and_destruction_0(int, int):
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
cmp DWORD PTR [rbp-4], 1
jne .L72
cmp DWORD PTR [rbp-8], 65535
jne .L72
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
call __cxa_atexit
mov eax, OFFSET FLAT:secretKey[abi:cxx11]
mov rdi, rax
call getSecretKey[abi:cxx11]()
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:secretKey[abi:cxx11]
mov edi, OFFSET FLAT:std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() [complete object destructor]
call __cxa_atexit
.L72:
nop
leave
ret
_GLOBAL__sub_I_getSecretKey[abi:cxx11]():
push rbp
mov rbp, rsp
mov esi, 65535
mov edi, 1
call __static_initialization_and_destruction_0(int, int)
pop rbp
ret
Sie sehen also, dass Sie den Code nicht mehr naiv nach interessanten Zeichenketten durchsuchen müssen, aber es geht um mehr. Sie müssen Haltepunkte setzen und verschiedene Werte überprüfen und versuchen, den Code logisch zu durchschauen, um ihn zu lösen. In diesem Beispiel sind die Symbole jedoch sichtbar, was eine Menge sensibler Informationen darüber verrät, was die Anwendung tut. Durch das Ausblenden der Symbole wird die Umgehung der Sicherheit schwieriger, wie Sie sehen können.