All pastes #591822 Raw Edit

Stuff

public text v1 · immutable
#591822 ·published 2007-06-27 12:42 UTC
rendered paste body
/* 
 * Linux Tibia Loader
 * by Primer
 *
 * Version 0.1
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <asm/ptrace.h>
#include <errno.h>
#include <elf.h>

#define HOST_MAX_SIZE 0x40
#define HOST_TO_PORT_SEP 0x64

/*
TODO:
- Find a way to not patch the executable.
*/

const char* tibia_server[10] = {"tibia01.cipsoft.com", "tibia02.cipsoft.com", "tibia03.cipsoft.com", "tibia04.cipsoft.com", "tibia05.cipsoft.com", 
				"login01.tibia.com", "login02.tibia.com", "login03.tibia.com", "login04.tibia.com", "login05.tibia.com"};

const char otserv_rsakey[]=
"10912013296739942927886096050899"
"55415282375029027981291234687579"
"37266291492576446330739696001110"
"60390723088861007265581882535850"
"34290575928276294364131085660290"
"93628212635953836686562675849720"
"62078627943109021801768106152175"
"50567108238764764442605581471797"
"07119674283982419152118103759076"
"030616683978566631413";

const char tibia_rsakey[]=
"12471045942682794300437644989798"
"55821678017079606970371640449048"
"62948569380850421396904597686953"
"87702239460423942818549828416906"
"85818022776120810279667243363194"
"48537811441719076484340922854929"
"27351730866137072710538289911899"
"94038080458464446472844991231648"
"79035103627004668521005328367415"
"259939915284902061793";

long change_string(char *pmem, unsigned long size, const char *str_old, const char *str_new)
{
	unsigned long i,j;
	int len = strlen(str_old) + 1;
	for(i=0,j=0; j < len; i++)
	{
		if(i >= size)
			return -1;
		
		if(pmem[i] == str_old[j])
			j++;
		else
			j=0;
	}
	
	i -= j;
	len = strlen(str_new) + 1;
	for(j=0; j < len; j++, i++)
		pmem[i] = str_new[j];
		
	return (long)(i - j);
}

int main(int argc, char *argv[]) {

    char host[HOST_MAX_SIZE]="localhost";
    unsigned long port=7171;
    char path[256]="./Tibia";
    
    unsigned long ad_bss;
    unsigned long ad_bss_size;
    unsigned long ad_rodata;
    unsigned long ad_rodata_size;

    if(argc > 3) strcpy(path, argv[3]);
    if(argc > 2) port = atol(argv[2]);
    if(argc > 1) strcpy(host, argv[1]);

    int fd;
    fd = open(path, O_RDWR);
    if(-1 == fd) {
        fprintf(stderr, "Failed to open %s.\n", path);
        return 1;
    }
    
    Elf32_Ehdr eh;
    int n;
    n = read(fd, &eh, sizeof(Elf32_Ehdr)); 
    if(n != sizeof(Elf32_Ehdr))
    {
    	fprintf(stderr, "Error reading Elf Header.\n");
    	close(fd);
        return 1;
    }
    
    if(-1 == lseek(fd, eh.e_shoff + (eh.e_shstrndx * eh.e_shentsize), SEEK_SET)) {
        fprintf(stderr, "Error in lseek.\n");
        close(fd);
        return 1;
    }
    
    Elf32_Shdr sh;
    n = read(fd, &sh, sizeof(Elf32_Shdr));
    if(n != sizeof(Elf32_Shdr))
    {
    	fprintf(stderr, "Error reading Elf Header(2).\n");
    	close(fd);
        return 1;
    }
    
    if(-1 == lseek(fd, sh.sh_offset, SEEK_SET)) {
        fprintf(stderr, "Error in lseek(2).\n");
        close(fd);
        return 1;
    }
    
    char *strtab = malloc(sh.sh_size);
    if(strtab == NULL)
    {
    	fprintf(stderr, "Error in malloc.\n");
        close(fd);
        return 1;
    }
    
    n = read(fd, strtab, sh.sh_size);
    if(n != sh.sh_size)
    {
    	fprintf(stderr, "Error reading Elf Header(3).\n");
    	close(fd);
        return 1;
    }
    
    int pos = 0;
    int pos_data = 0;
    int pos_rodata = 0;
    for(;;)
    {
    	if(pos > sh.sh_size)
    	{
    		fprintf(stderr, "Error searching for sections in strtab.\n");
        	close(fd);
        	return 1;
    	}
    	if(!pos_data && strcmp(strtab + pos, ".bss") == 0)
    		pos_data = pos;
    	else if(!pos_rodata && strcmp(strtab + pos, ".rodata") == 0)
    		pos_rodata = pos;
    	else if(pos_data && pos_rodata)
    		break;
    	
    	pos += strlen(strtab + pos) + 1;
    }
    free(strtab);
    
    int i;
    int step = 0;
    for(i=0; step < 2; i++)
    {
    	if(i >= eh.e_shnum)
    	{
    		fprintf(stderr, "Error searching for data sections in section header.\n");
        	close(fd);
        	return 1;
        }
    	
	    if(-1 == lseek(fd, eh.e_shoff + (i * eh.e_shentsize), SEEK_SET)) {
	        fprintf(stderr, "Error in lseek(3).\n");
	        close(fd);
	        return 1;
	    }
	    
	    n = read(fd, &sh, sizeof(Elf32_Shdr));
    	if(n != sizeof(Elf32_Shdr))
	    {
	    	fprintf(stderr, "Error reading Elf Header(4).\n");
	    	close(fd);
	        return 1;
	    }
	    
	    if(sh.sh_name == pos_data)
	    {
	    	ad_bss = sh.sh_addr;
	    	ad_bss_size = sh.sh_size;
	    	step++;
	    }
	    else if(sh.sh_name == pos_rodata)
	    {
	    	ad_rodata = sh.sh_addr;
	    	ad_rodata_size = sh.sh_size;
	    	
	    	// patching to make the section writeable
	    	sh.sh_flags = sh.sh_flags | SHF_WRITE;
	    	if(-1 == lseek(fd, eh.e_shoff + (i * eh.e_shentsize), SEEK_SET)) {
		        fprintf(stderr, "Error in lseek(4).\n");
		        close(fd);
		        return 1;
		    }
		    n = write(fd, &sh, sizeof(Elf32_Shdr));
	    	if(n != sizeof(Elf32_Shdr))
		    {
		    	fprintf(stderr, "Error writing Elf Header.\n");
		    	close(fd);
		        return 1;
		    }
		    
	    	step++;
	    }
    }
    
    close(fd);
    
    
    int pid;
    int wait_val;
    switch (pid = fork()) {
        case -1:
            perror("fork");
            break;
        case 0:
            if(-1 == ptrace(PTRACE_TRACEME, 0, NULL, NULL) && errno) {
                perror("ptrace(1)");
                return 1;
            }
            if(-1 == execl(path, path, NULL)) {
                perror("execl");
                return 1;
            }
            break;
        default:
            if(-1 == wait(&wait_val)) {
                perror("wait(1)");
                return 1;
            }
            
            int i,j;
            int counter=0;
            while (!WIFEXITED(wait_val)) {
                counter++;
                if(counter == 2) {
                	// change rsa key
                	char *pmem;
                	unsigned long data;
                	long pos;
                	
                	pmem = malloc(ad_rodata_size+sizeof(unsigned long));
                	
                	for(i=0; i<ad_rodata_size; i+=sizeof(unsigned long))
                	{
                		data = ptrace(PTRACE_PEEKDATA, pid, ad_rodata + i, NULL);
                        if(-1 == data && errno) {
                            perror("ptrace(2)");
                            return 1;
                        }
                        *((unsigned long *)(pmem + i)) = data;
                	}
                	
                	pos = change_string(pmem, ad_rodata_size, tibia_rsakey, otserv_rsakey);
                	if(-1 == pos)
                	{
                		fprintf(stderr, "RSA Key not found.\n");
                		return 1;
                	}
                	
                	for(i=0; i<strlen(otserv_rsakey); i+=sizeof(unsigned long))
                	{
                		if(-1 == ptrace(PTRACE_POKEDATA, pid, ad_rodata + pos + i, *((unsigned long *)(pmem + pos + i))) && errno) {
                            perror("ptrace(3)");
                            return 1;
                        }
                	}
                	
                	free(pmem);

                	// change host
                	pmem = malloc(ad_bss_size+sizeof(unsigned long));
                	for(i=0; i<ad_bss_size; i+=sizeof(unsigned long))
                	{
                		data = ptrace(PTRACE_PEEKDATA, pid, ad_bss + i, NULL);
                        	if(-1 == data && errno) {
                        	    perror("ptrace(4)");
                        	    return 1;
                        	}
                        	*((unsigned long *)(pmem + i)) = data;
                	}

			for(i=0; i<10; i++)
			{
				printf("%d %s %s\n", i, tibia_server[i], host);
               	 		pos = change_string(pmem, ad_bss_size, tibia_server[i], host);
               	 		if(-1 == pos)
               			{
               				fprintf(stderr, "Test server host not found.\n");
					return 1;
               	 		}
			}

                	for(i=0; i<strlen(host); i+=sizeof(unsigned long))
                	{
                		if(-1 == ptrace(PTRACE_POKEDATA, pid, ad_bss + pos + i, *((unsigned long *)(pmem + pos + i))) && errno) {
                            		perror("ptrace(5)");
                           		return 1;
                       		}
                	}
                	free(pmem);
                	
                	// change port
                	data = ptrace(PTRACE_PEEKDATA, pid, ad_bss + pos + HOST_TO_PORT_SEP, NULL);
                    if(-1 == data && errno) {
                        perror("ptrace(6)");
                        return 1;
                    }
                    data >>= 16;
                    data <<= 16;
                    data += (port & 0xFFFF);
                	if(-1 == ptrace(PTRACE_POKEDATA, pid, ad_bss + pos + HOST_TO_PORT_SEP, data) && errno) {
                        perror("ptrace(7)");
                        return 1;
                    }

					if(-1 == kill(pid, SIGALRM)) {
						perror("kill SIGALRM");
						return 1;
					}
                	if(-1 == ptrace(PTRACE_DETACH, pid, NULL, NULL) && errno) {
                    	perror("ptrace(5)");
                    	return 1;
                	}
                	return 0;
                }
                
                if(-1 == ptrace(PTRACE_CONT, pid, NULL, NULL) && errno) {
                    perror("ptrace(6)");
                    return 1;
                }
                if(-1 == wait(&wait_val)) {
                    perror("wait(2)");
                    return 1;
                }
            }
    }
    return 0;
}