Técnicas AntiCracking – Parte II – Eliminação de Informação Simbólica

Se um desenvolvedor deseja se inteirar de como age um cracker deve testar se seu programa gera informações simbólicas antes de lançá-lo no mercado. Ainda que não seja possível remover toda essa informação da estrutura de um programa, modificar alguns pontos críticos pode ser crucial para o sucesso ou não da proteção.

A eliminação total não ocorre porque programamos em linguagens de alto nível, como C e C++, que são convertidas em instruções processáveis através de um compilador. É o compilador que acaba gerando dados que servem como “pontos de referências” para quem investiga um código disassemblado.

Os compiladores costumam gerar informações simbólicas – para representar as lincagens – quando convertem as relações de importação e exportação de tabelas e extensões. Um programa com grande uso de DLLs, onde cada uma exporta uma grande quantidade de funções, necessitará de uma lista relacionando onde estão as funções exportadas, normalmente indicando o que elas fazem, o que é de grande serventia para os crackers.

Para confundir as referências que possam ser lógicas para o cracker, vale a pena exportar as funções com números ao invés de nomes. Essa pequena medida é eficiente no atraso do trabalho de um cracker, especialmente se usadas linguagens de orientadas a objetos, como C++ e Turbo Pascal.

Pessoalmente, nas poucas vezes que me deparei com códigos numéricos referenciando subrotinas acabei desistindo do trabalho devido à exaustiva e tediosa tarefa de só me ter números com pouco sentido.

A questão da informação simbólica é diferente com as linguagens que geram um assembly em bytecode. Estas linguagens muitas vezes usam códigos nominais internos para a referenciação dos endereços. Então, todos nomes internos são preservados quando o programa é compilado. Por esta estrutura nominal, os bytecodes são mais facilmente decompilados que os códigos binários.

As strings não podem ser simplesmente eliminadas, mas elas podem ser recolocadas com outras strings de forma que as referências cruzadas não fiquem prejudicadas.

Veja o código que mantém as informações simbólicas:

#include < stdio .h >
 
#define NMAX 1000
#define APR0 "O CRIVO DE ERASTOTENES\n"
#define APR1 "Codigo com informacao simbolica explicita\n"
#define APR2 "www.sawp.com.br \n\n"
 
int pilhaCrivo[NMAX];
 
 
void apresentacao(){
	printf(APR0);
	printf(APR1);
	printf(APR2);
}
 
void fazListaDeNumeros(){
	int i=0;
	for (i=2; i< =NMAX; i++) {
	        pilhaCrivo[i]=i;
	}
}
 
void mostra(void){
	int i,j;
	for (i=2; i<=NMAX; i++) {
	        if (pilhaCrivo[i]==i) {
	            printf("%d \n", i);
	            for (j=i+i; j<=NMAX; j+=i) {
	                pilhaCrivo[j]=0;
	            }
	        }
	    }
}
 
int main() {
	apresentacao();
	fazListaDeNumeros();
	mostra();
 
	return 1;
}

Agora veja o código abaixo, onde as informações simbólicas foram removidas:

#include < 8203099666.h >
#include < 1010011010.h >
#include < 75981212.h >
using std::string;
using std::cout;
 
#define N32MMX2 1000
#define APR1 "Htinlt%htr%nsktwrfhft%xnrgtqnhf%j}uqnhnyf3" 
#define APR2 "|||3xf|u3htr3gw" 
#define APR0 
T%HWN[T%IJ%JWFXYTYJSJX
 
 
int PH040x12[N32MMX2];
 
 
void rot13_d3c0d3(string & INx990012){
	const int kkk=5;
	int a5c11c0d3;
 
	for(int i=0;i< inx990012 .length();i++) {
		a5c11c0d3 = static_cast< int >(INx990012[i])- kkk;
		INx990012[i] =  static_cast< char >(a5c11c0d3);
	}
}
 
void st4rt3R_09833(){
	string h0xx3232122[] = {APR0, APR1, APR2};
 
	rot13_d3c0d3(h0xx3232122[0]);
	rot13_d3c0d3(h0xx3232122[1]);
	rot13_d3c0d3(h0xx3232122[2]);
 
	cout < < h0xx3232122[0] < < "\n" < < h0xx3232122[1] < < "\n" < < h0xx3232122[2] < < "\n\n";
}
 
 
void HP00x98765432(){
	int i=0;
	for (i=2; i <= N32MMX2; i++) {
	        PH040x12[i]=i;
	}
}
 
void IB00x98701234(void){
	int i,j;
	for (i=2; i <= N32MMX2; i++) {
	        if (PH040x12[i]==i) {
	            printf("%d \n", i);
	            for (j=i+i; j <= N32MMX2; j+=i) {
	                PH040x12[j]=0;
	            }
	        }
	    }
}
 
int main() {
	st4rt3R_09833();
	HP00x98765432();
	IB00x98701234();
 
	return 1;
}

Da mesma forma, comparemos o código em assembly:

	.file	"main.c"
	.section .rdata,"dr"
LC0:
	.ascii "O CRIVO DE ERASTOTENES\12\0"
	.align 4
LC1:
	.ascii "Codigo com informacao simbolica explicita\12\0"
LC2:
	.ascii "www.sawp.com.br \12\12\0"
	.text
.globl _apresentacao
	.def	_apresentacao;	.scl	2;	.type	32;	.endef
_apresentacao:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	$LC0, (%esp)
	call	_printf
	movl	$LC1, (%esp)
	call	_printf
	movl	$LC2, (%esp)
	call	_printf
	leave
	ret
.globl _fazListaDeNumeros
	.def	_fazListaDeNumeros;	.scl	2;	.type	32;	.endef
_fazListaDeNumeros:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	$0, -4(%ebp)
	movl	$2, -4(%ebp)
L3:
	cmpl	$1000, -4(%ebp)
	jg	L2
	movl	-4(%ebp), %edx
	movl	-4(%ebp), %eax
	movl	%eax, _pilhaCrivo(,%edx,4)
	leal	-4(%ebp), %eax
	incl	(%eax)
	jmp	L3
L2:
	leave
	ret
	.section .rdata,"dr"
LC3:
	.ascii "%d \12\0"
	.text
.globl _mostra
	.def	_mostra;	.scl	2;	.type	32;	.endef
_mostra:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	movl	$2, -4(%ebp)
L7:
	cmpl	$1000, -4(%ebp)
	jg	L6
	movl	-4(%ebp), %eax
	movl	_pilhaCrivo(,%eax,4), %eax
	cmpl	-4(%ebp), %eax
	jne	L9
	movl	-4(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	$LC3, (%esp)
	call	_printf
	movl	-4(%ebp), %eax
	addl	-4(%ebp), %eax
	movl	%eax, -8(%ebp)
L11:
	cmpl	$1000, -8(%ebp)
	jg	L9
	movl	-8(%ebp), %eax
	movl	$0, _pilhaCrivo(,%eax,4)
	movl	-4(%ebp), %edx
	leal	-8(%ebp), %eax
	addl	%edx, (%eax)
	jmp	L11
L9:
	leal	-4(%ebp), %eax
	incl	(%eax)
	jmp	L7
L6:
	leave
	ret
	.def	___main;	.scl	2;	.type	32;	.endef
.globl _main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	addl	$15, %eax
	addl	$15, %eax
	shrl	$4, %eax
	sall	$4, %eax
	movl	%eax, -4(%ebp)
	movl	-4(%ebp), %eax
	call	__alloca
	call	___main
	call	_apresentacao
	call	_fazListaDeNumeros
	call	_mostra
	movl	$1, %eax
	leave
	ret
	.comm	_pilhaCrivo, 4000	 # 4000
	.def	_printf;	.scl	2;	.type	32;	.endef

Agora o mesmo código sem informações simbólicas explícitas:

	.file	"main.cpp"
	.text
	.align 2
	.def	__ZSt17__verify_groupingPKcjRKSs;	.scl	3;	.type	32;	.endef
__ZSt17__verify_groupingPKcjRKSs:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$40, %esp
	movl	16(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNKSs4sizeEv
	decl	%eax
	movl	%eax, -4(%ebp)
	movl	12(%ebp), %eax
	decl	%eax
	movl	%eax, -12(%ebp)
	leal	-12(%ebp), %eax
	movl	%eax, 4(%esp)
	leal	-4(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZSt3minIjERKT_S2_S2_
	movl	(%eax), %eax
	movl	%eax, -8(%ebp)
	movl	-4(%ebp), %eax
	movl	%eax, -16(%ebp)
	movb	$1, -17(%ebp)
	movl	$0, -24(%ebp)
L2:
	movl	-24(%ebp), %eax
	cmpl	-8(%ebp), %eax
	jae	L5
	cmpb	$0, -17(%ebp)
	je	L5
	movl	-16(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	16(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNKSsixEj
	movsbl	(%eax),%edx
	movl	8(%ebp), %eax
	addl	-24(%ebp), %eax
	movsbl	(%eax),%eax
	cmpl	%eax, %edx
	sete	%al
	movb	%al, -17(%ebp)
	leal	-16(%ebp), %eax
	decl	(%eax)
	leal	-24(%ebp), %eax
	incl	(%eax)
	jmp	L2
L5:
	cmpl	$0, -16(%ebp)
	je	L6
	cmpb	$0, -17(%ebp)
	je	L6
	movl	-16(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	16(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNKSsixEj
	movsbl	(%eax),%edx
	movl	8(%ebp), %eax
	addl	-8(%ebp), %eax
	movsbl	(%eax),%eax
	cmpl	%eax, %edx
	sete	%al
	movb	%al, -17(%ebp)
	leal	-16(%ebp), %eax
	decl	(%eax)
	jmp	L5
L6:
	movl	$0, 4(%esp)
	movl	16(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNKSsixEj
	movsbl	(%eax),%edx
	movl	8(%ebp), %eax
	addl	-8(%ebp), %eax
	movsbl	(%eax),%eax
	cmpl	%eax, %edx
	jg	L8
	movzbl	-17(%ebp), %eax
	andl	$1, %eax
	movb	%al, -25(%ebp)
	jmp	L9
L8:
	movb	$0, -25(%ebp)
L9:
	movzbl	-25(%ebp), %eax
	movb	%al, -17(%ebp)
	movzbl	-17(%ebp), %eax
	leave
	ret
.lcomm __ZSt8__ioinit,16
.globl _PH040x12
	.bss
	.align 32
_PH040x12:
	.space 4000
	.text
	.align 2
.globl __Z12rot13_d3c0d3RSs
	.def	__Z12rot13_d3c0d3RSs;	.scl	2;	.type	32;	.endef
__Z12rot13_d3c0d3RSs:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	movl	$5, -4(%ebp)
	movl	$0, -12(%ebp)
L11:
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNKSs6lengthEv
	cmpl	%eax, -12(%ebp)
	jae	L10
	movl	-12(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSsixEj
	movsbl	(%eax),%eax
	subl	$5, %eax
	movl	%eax, -8(%ebp)
	movl	-12(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSsixEj
	movl	%eax, %edx
	movl	-8(%ebp), %eax
	movb	%al, (%edx)
	leal	-12(%ebp), %eax
	incl	(%eax)
	jmp	L11
L10:
	leave
	ret
	.def	__Unwind_SjLj_Resume;	.scl	2;	.type	32;	.endef
	.def	___gxx_personality_sj0;	.scl	2;	.type	32;	.endef
	.def	__Unwind_SjLj_Register;	.scl	2;	.type	32;	.endef
	.def	__Unwind_SjLj_Unregister;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
LC0:
	.ascii "T%HWN[T%IJ%JWFXYTYJSJX\0"
	.align 4
LC1:
	.ascii "Htinlt%htr%nsktwrfhft%xnrgtqnhf%j}uqnhnyf3\0"
LC2:
	.ascii "|||3xf|u3htr3gw\0"
LC3:
	.ascii "\12\0"
LC4:
	.ascii "\12\12\0"
	.text
	.align 2
.globl __Z13st4rt3R_09833v
	.def	__Z13st4rt3R_09833v;	.scl	2;	.type	32;	.endef
__Z13st4rt3R_09833v:
	pushl	%ebp
	movl	%esp, %ebp
	pushl	%edi
	pushl	%esi
	pushl	%ebx
	subl	$172, %esp
	movl	$___gxx_personality_sj0, -84(%ebp)
	movl	$LLSDA1426, -80(%ebp)
	leal	-76(%ebp), %eax
	leal	-24(%ebp), %edx
	movl	%edx, (%eax)
	movl	$L47, %edx
	movl	%edx, 4(%eax)
	movl	%esp, 8(%eax)
	leal	-108(%ebp), %eax
	movl	%eax, (%esp)
	call	__Unwind_SjLj_Register
	leal	-40(%ebp), %eax
	movl	%eax, -112(%ebp)
	movl	-112(%ebp), %edx
	movl	%edx, -116(%ebp)
	movl	$2, -120(%ebp)
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcEC1Ev
	leal	-56(%ebp), %eax
	movl	%eax, 8(%esp)
	movl	$LC0, 4(%esp)
	movl	-116(%ebp), %eax
	movl	%eax, (%esp)
	movl	$4, -104(%ebp)
	call	__ZNSsC1EPKcRKSaIcE
	jmp	L16
L15:
	movl	-128(%ebp), %edx
	movl	%edx, -124(%ebp)
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcED1Ev
	movl	-124(%ebp), %eax
	movl	%eax, -128(%ebp)
L17:
	jmp	L27
L16:
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcED1Ev
	addl	$4, -116(%ebp)
	decl	-120(%ebp)
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcEC1Ev
	leal	-56(%ebp), %eax
	movl	%eax, 8(%esp)
	movl	$LC1, 4(%esp)
	movl	-116(%ebp), %edx
	movl	%edx, (%esp)
	movl	$3, -104(%ebp)
	call	__ZNSsC1EPKcRKSaIcE
	jmp	L20
L19:
	movl	-128(%ebp), %eax
	movl	%eax, -132(%ebp)
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcED1Ev
	movl	-132(%ebp), %edx
	movl	%edx, -128(%ebp)
L21:
	jmp	L27
L20:
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcED1Ev
	addl	$4, -116(%ebp)
	decl	-120(%ebp)
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcEC1Ev
	leal	-56(%ebp), %eax
	movl	%eax, 8(%esp)
	movl	$LC2, 4(%esp)
	movl	-116(%ebp), %eax
	movl	%eax, (%esp)
	movl	$2, -104(%ebp)
	call	__ZNSsC1EPKcRKSaIcE
	jmp	L24
L23:
	movl	-128(%ebp), %edx
	movl	%edx, -136(%ebp)
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcED1Ev
	movl	-136(%ebp), %eax
	movl	%eax, -128(%ebp)
L25:
	jmp	L27
L24:
	leal	-56(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZNSaIcED1Ev
	decl	-120(%ebp)
	jmp	L28
L27:
	movl	-128(%ebp), %edx
	movl	%edx, -140(%ebp)
	cmpl	$0, -112(%ebp)
	je	L30
	movl	$2, %eax
	subl	-120(%ebp), %eax
	movl	%eax, -144(%ebp)
	movl	-144(%ebp), %eax
	sall	$2, %eax
	movl	-112(%ebp), %edx
	addl	%eax, %edx
	movl	%edx, -144(%ebp)
L31:
	movl	-144(%ebp), %eax
	cmpl	%eax, -112(%ebp)
	je	L30
	subl	$4, -144(%ebp)
	movl	-144(%ebp), %edx
	movl	%edx, (%esp)
	movl	$0, -104(%ebp)
	call	__ZNSsD1Ev
	jmp	L31
L30:
	movl	-140(%ebp), %eax
	movl	%eax, -128(%ebp)
L33:
	movl	-128(%ebp), %edx
	movl	%edx, (%esp)
	movl	$-1, -104(%ebp)
	call	__Unwind_SjLj_Resume
L28:
	leal	-40(%ebp), %eax
	movl	%eax, (%esp)
	movl	$1, -104(%ebp)
	call	__Z12rot13_d3c0d3RSs
	leal	-40(%ebp), %eax
	addl	$4, %eax
	movl	%eax, (%esp)
	call	__Z12rot13_d3c0d3RSs
	leal	-40(%ebp), %eax
	addl	$8, %eax
	movl	%eax, (%esp)
	call	__Z12rot13_d3c0d3RSs
	leal	-40(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	$__ZSt4cout, (%esp)
	call	__ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E
	movl	$LC3, 4(%esp)
	movl	%eax, (%esp)
	call	__ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
	leal	-40(%ebp), %edx
	addl	$4, %edx
	movl	%edx, 4(%esp)
	movl	%eax, (%esp)
	call	__ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E
	movl	$LC3, 4(%esp)
	movl	%eax, (%esp)
	call	__ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
	leal	-40(%ebp), %edx
	addl	$8, %edx
	movl	%edx, 4(%esp)
	movl	%eax, (%esp)
	call	__ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E
	movl	$LC4, 4(%esp)
	movl	%eax, (%esp)
	call	__ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
	jmp	L36
L47:
	leal	24(%ebp), %ebp
	movl	-104(%ebp), %eax
	movl	%eax, -156(%ebp)
	movl	-100(%ebp), %edx
	movl	%edx, -128(%ebp)
	cmpl	$1, -156(%ebp)
	je	L23
	cmpl	$2, -156(%ebp)
	je	L19
	cmpl	$3, -156(%ebp)
	je	L15
L35:
	movl	-128(%ebp), %eax
	movl	%eax, -148(%ebp)
	leal	-40(%ebp), %eax
	testl	%eax, %eax
	je	L38
	leal	-40(%ebp), %edx
	movl	%edx, -152(%ebp)
	addl	$12, -152(%ebp)
L39:
	leal	-40(%ebp), %eax
	cmpl	-152(%ebp), %eax
	je	L38
	subl	$4, -152(%ebp)
	movl	-152(%ebp), %eax
	movl	%eax, (%esp)
	movl	$0, -104(%ebp)
	call	__ZNSsD1Ev
	jmp	L39
L38:
	movl	-148(%ebp), %edx
	movl	%edx, -128(%ebp)
L41:
	movl	-128(%ebp), %eax
	movl	%eax, (%esp)
	movl	$-1, -104(%ebp)
	call	__Unwind_SjLj_Resume
L36:
	leal	-40(%ebp), %eax
	testl	%eax, %eax
	je	L14
	leal	-40(%ebp), %edx
	movl	%edx, -152(%ebp)
	addl	$12, -152(%ebp)
L45:
	leal	-40(%ebp), %eax
	cmpl	-152(%ebp), %eax
	je	L14
	subl	$4, -152(%ebp)
	movl	-152(%ebp), %eax
	movl	%eax, (%esp)
	movl	$-1, -104(%ebp)
	call	__ZNSsD1Ev
	jmp	L45
L14:
	leal	-108(%ebp), %eax
	movl	%eax, (%esp)
	call	__Unwind_SjLj_Unregister
	addl	$172, %esp
	popl	%ebx
	popl	%esi
	popl	%edi
	popl	%ebp
	ret
	.section	.gcc_except_table,"dr"
LLSDA1426:
	.byte	0xff
	.byte	0xff
	.byte	0x1
	.uleb128 LLSDACSE1426-LLSDACSB1426
LLSDACSB1426:
	.uleb128 0x0
	.uleb128 0x0
	.uleb128 0x1
	.uleb128 0x0
	.uleb128 0x2
	.uleb128 0x0
	.uleb128 0x3
	.uleb128 0x0
LLSDACSE1426:
	.text
	.align 2
.globl __Z13HP00x98765432v
	.def	__Z13HP00x98765432v;	.scl	2;	.type	32;	.endef
__Z13HP00x98765432v:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	$0, -4(%ebp)
	movl	$2, -4(%ebp)
L49:
	cmpl	$1000, -4(%ebp)
	jg	L48
	movl	-4(%ebp), %edx
	movl	-4(%ebp), %eax
	movl	%eax, _PH040x12(,%edx,4)
	leal	-4(%ebp), %eax
	incl	(%eax)
	jmp	L49
L48:
	leave
	ret
	.section .rdata,"dr"
LC5:
	.ascii "%d \12\0"
	.text
	.align 2
.globl __Z13IB00x98701234v
	.def	__Z13IB00x98701234v;	.scl	2;	.type	32;	.endef
__Z13IB00x98701234v:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	movl	$2, -4(%ebp)
L53:
	cmpl	$1000, -4(%ebp)
	jg	L52
	movl	-4(%ebp), %eax
	movl	_PH040x12(,%eax,4), %eax
	cmpl	-4(%ebp), %eax
	jne	L55
	movl	-4(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	$LC5, (%esp)
	call	_printf
	movl	-4(%ebp), %eax
	addl	-4(%ebp), %eax
	movl	%eax, -8(%ebp)
L57:
	cmpl	$1000, -8(%ebp)
	jg	L55
	movl	-8(%ebp), %eax
	movl	$0, _PH040x12(,%eax,4)
	movl	-4(%ebp), %edx
	leal	-8(%ebp), %eax
	addl	%edx, (%eax)
	jmp	L57
L55:
	leal	-4(%ebp), %eax
	incl	(%eax)
	jmp	L53
L52:
	leave
	ret
	.def	___main;	.scl	2;	.type	32;	.endef
	.align 2
.globl _main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	addl	$15, %eax
	addl	$15, %eax
	shrl	$4, %eax
	sall	$4, %eax
	movl	%eax, -4(%ebp)
	movl	-4(%ebp), %eax
	call	__alloca
	call	___main
	call	__Z13st4rt3R_09833v
	call	__Z13HP00x98765432v
	call	__Z13IB00x98701234v
	movl	$1, %eax
	leave
	ret
	.section	.text$_ZSt3minIjERKT_S2_S2_,"x"
	.linkonce discard
	.align 2
.globl __ZSt3minIjERKT_S2_S2_
	.def	__ZSt3minIjERKT_S2_S2_;	.scl	2;	.type	32;	.endef
__ZSt3minIjERKT_S2_S2_:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$4, %esp
	movl	12(%ebp), %eax
	movl	8(%ebp), %edx
	movl	(%eax), %eax
	cmpl	(%edx), %eax
	jae	L62
	movl	12(%ebp), %eax
	movl	%eax, -4(%ebp)
	jmp	L61
L62:
	movl	8(%ebp), %eax
	movl	%eax, -4(%ebp)
L61:
	movl	-4(%ebp), %eax
	leave
	ret
	.text
	.align 2
	.def	__Z41__static_initialization_and_destruction_0ii;	.scl	3;	.type	32;	.endef
__Z41__static_initialization_and_destruction_0ii:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	cmpl	$65535, 12(%ebp)
	jne	L64
	cmpl	$1, 8(%ebp)
	jne	L64
	movl	$__ZSt8__ioinit, (%esp)
	call	__ZNSt8ios_base4InitC1Ev
L64:
	cmpl	$65535, 12(%ebp)
	jne	L63
	cmpl	$0, 8(%ebp)
	jne	L63
	movl	$__ZSt8__ioinit, (%esp)
	call	__ZNSt8ios_base4InitD1Ev
L63:
	leave
	ret
	.align 2
	.def	__GLOBAL__I_PH040x12;	.scl	3;	.type	32;	.endef
__GLOBAL__I_PH040x12:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	$65535, 4(%esp)
	movl	$1, (%esp)
	call	__Z41__static_initialization_and_destruction_0ii
	leave
	ret
	.section	.ctors,"w"
	.align 4
	.long	__GLOBAL__I_PH040x12
	.text
	.align 2
	.def	__GLOBAL__D_PH040x12;	.scl	3;	.type	32;	.endef
__GLOBAL__D_PH040x12:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	$65535, 4(%esp)
	movl	$0, (%esp)
	call	__Z41__static_initialization_and_destruction_0ii
	leave
	ret
	.section	.dtors,"w"
	.align 4
	.long	__GLOBAL__D_PH040x12
	.def	__ZNSt8ios_base4InitD1Ev;	.scl	2;	.type	32;	.endef
	.def	_printf;	.scl	2;	.type	32;	.endef
	.def	__ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc;	.scl	2;	.type	32;	.endef
	.def	__ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E;	.scl	2;	.type	32;	.endef
	.def	__ZNSsD1Ev;	.scl	2;	.type	32;	.endef
	.def	__ZNSsC1EPKcRKSaIcE;	.scl	2;	.type	32;	.endef
	.def	__ZNSaIcED1Ev;	.scl	2;	.type	32;	.endef
	.def	__ZNSaIcEC1Ev;	.scl	2;	.type	32;	.endef
	.def	__ZNSsixEj;	.scl	2;	.type	32;	.endef
	.def	__ZNKSs6lengthEv;	.scl	2;	.type	32;	.endef
	.def	__ZNSt8ios_base4InitC1Ev;	.scl	2;	.type	32;	.endef
	.def	__ZNKSsixEj;	.scl	2;	.type	32;	.endef
	.def	__ZNKSs4sizeEv;	.scl	2;	.type	32;	.endef

Ambos códigos realizam a mesma tarefa: exibir a mensagem “O CRIVO DE ERASTOTENES. Codigo com informacao simbolica explicita. www.sawp.com.br” e em seguida-se calcula os números primos existentes de 2 à 1000.

Contudo, claramente observamos no segundo código que as strings não visíveis. Isso faz com que seja quase impossível para o cracker saber sobre o que se trata aquela informação, pois ele precisaria do código responsável pela decriptação da informação simbólica. No caso, a função responsável por tornar o texto visível para o usuário e invisível para o cracker é a “rot13_d3c0d3”.

Para quem tiver curiosidade, rot13_d3c0d3 substitui um caractere por outro que têm seu asccii-13. Veja:

void rot13ASC_decode(string & input){
	const int key=13;
	int asciicode;
 
	for(int i=0;i < input .length();i++) {
		asciicode = static_cast< int >(input[i])- key;
		input[i] =  static_cast< char >(asciicode);
	}
}

Normalmente os crackers se deparam com codificações reversíveis, como BASE64, rot13,rot64, algum algoritmo derivado de Cifras de César-Vigenere ou algum algoritmo de transposição.

Notamos então que colocar as constantes em texto explícito é uma forma extremamente vulnerável por deixar pontos de referências para os crackers se localizarem na nossa aplicação.

Observamos também que o código assembly com as informações simbólicas removidas é muito mais extenso e possui muito mais instruções que o código original. Isso reforça uma das desvantagens descritas na PARTE 1 sobre anti-cracking: sempre há perda de desempenho ao implementar técnicas anticracking.

Este é um ponto importante e que deve sempre estar na cabeça do desenvolvedor. No nosso pequeno exemplo já tivemos um considerável aumento de instruções. E este crescimento é propagado quão maior for o código da aplicação, representando significativa perda de eficiência.

Deve-se ficar claro que o código aqui apresentado é apenas para exemplificar. Alguém que necessite proteger sua aplicação, certamente está trabalhando em um projeto grande, com vários arquivos-fontes, muitas classes e funções. Então, obviamente, não há como eliminar as informações simbólicas “na mão”.

O que as empresas que empregam técnicas anti-cracking fazem é construir parsers especiais e scripts especiais de compilação. Desta forma, o código ao invés de ser enviado direto para o compilador, são transformados por estes scripts em um código de sem informações simbólicas destes e só então são compilados.