Cóż,zgodnie z zasadą nie kijem go to pałą,poradziłem sobie w taki sposób,że zdefiniowałem makra zamiast funkcji inline
Jednak używanie ich nie przynosiło do końca takiego rezultatu jak chciałem.Oto testowy program:
#include <iostream>
using namespace std;
/* Let's assume such operations were generated(in order of applying):
1.Bitwise negation
2.exlusive or with value 50
3.adding 60
Macros for such combination have look:*/
#define SET(x) (((~(x))^50)+60)
#define GET(x) (~(((x)-60)^50))
int main(int argc, const char* argv[])
{
int a;
//encryption start
a=SET(257);
//encryption end
cout<<"obfuscated a="<<a<<endl;
cout<<"decrypted a(should be 257))="<<GET(a)<<endl;
return 0;
}
Kompilacja w trybie release w włączoną flagą /Ox daje rezultat:
; 18 : int a;
; 19 : //encryption start
; 20 : a=SET(257);
; 21 : //encryption end
; 22 : cout<<"obfuscated a="<<a<<endl;
push -248 ; ffffff08H //**tutaj ładnie schowało wartość 257**
push OFFSET FLAT:??_C@_0O@BJAKDLLP@obfuscated?5a?$DN?$AA@
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov esi, eax
push 10 ; 0000000aH
mov ecx, esi
call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
mov ecx, esi
call ?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ ; std::basic_ostream<char,std::char_traits<char> >::flush
; 23 : cout<<"decrypted a(should be 257))="<<GET(a)<<endl;
push 257 ; 00000101H **a tutaj dupa jak Słońce widziane z orbity Merkurego,cały wysiłek włożony w ukrycie wystąpienia tej wartości w kodzie właśnie poszedł się yebać**
push OFFSET FLAT:??_C@_0BN@BHBFMIJM@decrypted?5a?$CIshould?5be?5257?$CJ?$CJ?$DN?$AA@
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov esi, eax
push 10 ; 0000000aH
mov ecx, esi
call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
mov ecx, esi
call ?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ ; std::basic_ostream<char,std::char_traits<char> >::flush
Kombinowałem,góglowałem i w końcu okazało się,że Brat lukasz1235 miał rację-zmiana definicji na:
volatile int a;
daje asemblerowy kod:
; 18 : volatile int a;//volatile forces compiler to directly use memory cell instead of any precalculations
; 19 : //encryption start
; 20 : a=SET(257);
mov DWORD PTR _a$[esp+8], -248 ; ffffff08H **piękne schowanie rzeczywistej wartości i to jeszcze zoptymalizowane do stałej.Me like ^^ **
; 21 : //encryption end
; 22 : cout<<"obfuscated a="<<a<<endl;
mov eax, DWORD PTR _a$[esp+8]
push eax
push OFFSET FLAT:$SG9676
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov esi, eax
push 10 ; 0000000aH
mov ecx, esi
call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
mov ecx, esi
call ?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ ; std::basic_ostream<char,std::char_traits<char> >::flush
; 23 : cout<<"decrypted a(should be 257))="<<GET(a)<<endl;
mov ecx, DWORD PTR _a$[esp+8] //**a tutaj ślicznie rozwinięte i zoptymalizowane instrucje z makra GET bez ujawniania wartości**
sub ecx, 60 ; 0000003cH
xor ecx, 50 ; 00000032H
not ecx
push ecx
push OFFSET FLAT:$SG9679
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<<std::char_traits<char> >
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov esi, eax
push 10 ; 0000000aH
mov ecx, esi
call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
mov ecx, esi
call ?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ ; std::basic_ostream<char,std::char_traits<char> >::flush
HA!Żeby było weselej to okazuje się,że po dodaniu tego volatile do zmiennej a kompilator odzyskał znienacka umiejętność do prawidłowej interpretacji __forceinline! :O i teraz nie wywołuje mi funkcji callem tylko wrzuca jej ciało do kodu jak Swaróg przykazał.Jaja jak berety normalnie,a tak na poważnie to wie ktoś,czemu właśnie tak się dzieje?