Efter några månader så har jag fortsatt studien av Online Highscore och utvecklat en lösning där man laddar upp Namn & Score, samt en hashnyckel till php scritpet. Hash nyckeln beräknas på klienten och även på Servern.
För att kunna följa med denna tutorial så hittar du del 1 här: Online Highscore del 1.
C kod för Del 2: Ladda hem
Php koden hittar du i del 1 samt här i del 2 och får klippa och klistra lite.
MODIFIERING AV insert_highscore.php
Kod:
<? function getParam($name, $from, $link) { if (!array_key_exists($name, $from)) {return NULL;} $value = mysql_real_escape_string(urldecode(trim(strip_tags ($from[$name]))), $link); return $value; } $con = mysql_connect("localhost","anvandarnamn","losenord"); if(!$con) { die( "Kunde inte ansluta till databasen"); } @mysql_select_db(game_highscore) or die( "Kunde inte hitta databasen"); $playername=getParam('playername', $_POST, $con); $score=getParam('score', $_POST, $con); $thehash = getParam('thehash', $_POST, $con); $thehash = strtolower($thehash); $thehash = str_replace(' ', '', $thehash); $key = "NYCKEL"; $combine = sprintf("%s%s",$score,$key); $result = sha1($combine); if(strcmp($result,$thehash)==0) { $query = "INSERT INTO game_highscore VALUES ('','$score','$playername')"; mysql_query($query); } else { echo 'CHEAT DETECTED! ABORTING!'; } mysql_close(); ?>
Kod:
$thehash = getParam('thehash', $_POST, $con);
Kod:
$thehash = strtolower($thehash);
Kod:
$thehash = str_replace(' ', '', $thehash);
Kod:
$key = "NYCKEL";
Kod:
$combine = sprintf("%s%s",$score,$key);
Kod:
$result = sha1($combine);
Kod:
if(strcmp($result,$thehash)==0) { $query = "INSERT INTO highscore VALUES ('','$score','$playername')"; mysql_query($query); } else { echo 'CHEAT DETECTED! ABORTING!'; }
Om strängarna är identiska så sätter vi in highscore i databasen.
Stämmer inte strängarna så medelar vi att spelaren försökt att fuska, och vi avbryter.
Modifiering av test_highscore.c
Kod:
#include <string.h> #include <stdlib.h> #include <stdio.h> #include <curl/curl.h> #include "sha1.h" char createdkey[100]; //den nyckel vi skapar för SHA1 hashen char storeme[100]; //temporär sträng char alphabet[27]; //alpabetet A-Z void alphabet_inorder(char[]); //skapa alfabetet i ordning A-Z i en array void shuffle(char[]); //blanda om bokstäverna i random ordning int find_char(char y[],char c); //hitta en bokstav i en array void create_key(char alphabet[]); //skapa din nyckel char alphabet[27]; //array för att hålla alfabetet int main() { CURL *curl; CURLcode res; char name[20]; //variabeln där vi sparar namnet char msg[200]; //medelandet vi skickar till hemsidan med CURL char score[20]; //spelarens poäng SHA1_CTX context; //skapa en SHA1 context uint8_t digest[20]; //hashnyckeln då den bearbetas till HEX char sendhash[100]; //hash strängen vi skickar till hemsidan char hashme[100]; //den text sträng vi skapar hash nyckeln från //skapa alfabetet, randomisera det, och skapa nyckeln utifrån alfabetet. alphabet_inorder(alphabet); shuffle(alphabet); create_key(alphabet); /* In windows, this will init the winsock stuff */ curl_global_init(CURL_GLOBAL_ALL); /* get a curl handle */ curl = curl_easy_init(); //läs in spelarens namn och poäng // scanf = primitivt, space funkar ej, men duger för detta exempel. printf("Enter name:"); scanf("%s",name); printf("\nEnter Score:"); scanf("%s",score); /* get a curl handle */ curl = curl_easy_init(); if(curl) { sprintf(hashme,"%s%s",score,createdkey); //skapa strängen som vi vill hasha //initiera SHA1 SHA1_Init(&context); //uppdatera SHA1 med vad vi vill hasha, samt längden på strängen SHA1_Update(&context, (uint8_t*)hashme, strlen(hashme)); //hasha strängen och spara den i digest SHA1_Final(&context, digest); //konvertera digest till hex och spara den i "sendhash" variabeln digest_to_hex(digest, sendhash); //vi har nu vår hash-sträng klar för att skickas upp till hemsidan //skriv in medelandet vi vill skicka till hemsidan med CURL sprintf(msg,"playername=%s&score=%s&thehash=%s&project=curl",name,score,sendhash); /* First set the URL that is about to receive our POST. This URL can just as well be a https:// URL if that is what should receive the data. */ curl_easy_setopt(curl, CURLOPT_URL, "http://www.dinhemsida.se/highscore/insert_highscore.php"); /* Now specify the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS,msg); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if(res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } /* always cleanup */ curl_easy_cleanup(curl); } return 0; } /*hämta en bokstav ur den randomiserade arrayen detta medför att nyckeln skapas olika i minnet varje gång, vilket gör det svårare för nyfikna att kunna luska ut den*/ void create_key(char alphabet[]) { char pos=0; pos = find_char(alphabet,'N'); storeme[0] = alphabet[pos]; pos = find_char(alphabet,'Y'); storeme[1] = alphabet[pos]; pos = find_char(alphabet,'C'); storeme[2] = alphabet[pos]; pos = find_char(alphabet,'K'); storeme[3] = alphabet[pos]; pos = find_char(alphabet,'E'); storeme[4] = alphabet[pos]; pos = find_char(alphabet,'L'); storeme[5] = '\0'; //end //om man vill skriva mellanslag: // storeme[5] = ' '; sprintf(createdkey,"%s",storeme); } //Notera: Detta är bara stora bokstäver A-Z void alphabet_inorder(char x[]) { int i; x[0] = 'A'; for(i=1;i<26;i++) { x[i]= x[0]+i; } } void shuffle(char x[]) { int i; char temp; int rand_index; srand(time(0)); for(i=0;i<26;i++) { rand_index = rand()%26; temp = x[i]; x[i] = x[rand_index]; x[rand_index] = temp; } x[26] = '\0'; } int find_char(char y[],char c) { int i=0; int found = 0; while(!found) { if(y[i] == c) { found=1; return i; } i++; } }
En viktig aspekt att lyfta fram är följande:
Vi vill inte skylta med vår hashnyckel "NYCKEL" (tempnamn).
Skriver man:
char *key = "NYCKEL";
så räcker det med att man öppnar exe filen och tittar igenom den för att hitta teckensträngen.
För att dölja detta har man 2 alternativ:
1. Koda en lösning som skapar nyckeln
2. Köra upx exe packare och ta bort UPX texten i .exe filen med hjälp av en hexedtor så att den ej går att packa upp igen
3. Kombinera 1 + 2;
I exemplet ovan så valde jag att skapa en nyckel genom randomisering.
1. Skapa alfabetet (lägg till fler tecken om du vill)
2. Randomisera ordningen på alfabetet med srand(time(0));
3. Skapa nyckeln genom att söka efter önskad bokstav i strängen.
Gör vi detta så kommer minnet aldrig att se lika dant ut då vi skapar vår lösenords sträng, samt att den inte finns synligt som text i .exe filen.
Hämta Highscore från hemsidan - PHP
För att ådstakomma detta så föränklar vi först tio top listan så att vi får den till ett enklare format som vi lättare kan parsa igenom.
Vi skapar en ny fil: simple_score.php
Kod:
<? $con = mysql_connect("localhost","anvandarnamn","losenord"); if(!$con) { die( "Unable to connect to database"); } @mysql_select_db(dream_code_se) or die( "Unable to select database"); $query="SELECT * FROM highscore ORDER BY score DESC LIMIT 0,10"; mysql_real_escape_string($score); $result=mysql_query($query); mysql_real_escape_string($result); $num=mysql_numrows($result); $i=0; while ($i < $num) { $playername=mysql_result($result,$i,"playername"); $score=mysql_result($result,$i,"score"); echo "$playername,$score,"; $i++; } mysql_close(); ?>
Kod:
while ($i < $num) { $playername=mysql_result($result,$i,"playername"); $score=mysql_result($result,$i,"score"); echo "$playername,$score,"; $i++; }
Hämta Highscore från hemsidan - CURL C kod
Kod:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> //en enkel struct för en string med pekare och dess längd. struct string { char *ptr; size_t len; }; //struct för highscore typedef struct highscore_table { char name[80]; char score[80]; }highscore_table; highscore_table test_highscore[10]; //skapa en highscore table med rum för 10st spelare //initiera strängen och lägg till endline void init_string(struct string *s) { s->len = 0; s->ptr = malloc(s->len+1); if (s->ptr == NULL) { fprintf(stderr, "malloc() failed\n"); exit(EXIT_FAILURE); } s->ptr[0] = '\0'; } //För att CURL ska kunna skriva till en char sträng så använder vi oss av denna: size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s) { size_t new_len = s->len + size*nmemb; s->ptr = realloc(s->ptr, new_len+1); if (s->ptr == NULL) { fprintf(stderr, "realloc() failed\n"); exit(EXIT_FAILURE); } memcpy(s->ptr+s->len, ptr, size*nmemb); s->ptr[new_len] = '\0'; s->len = new_len; return size*nmemb; } //rensa highscore table void clear_highscore_table() { int i = 0,j=0; for(i=0;i<10;i++) { for(j=0;j<80;j++) { test_highscore[i].name[j] = '\0'; test_highscore[i].score[j] = '\0'; } } } void Parse_Highscore(char *hsstring) { int i=0,j=0; int count=0; int current_player=0; int current_score=0; int comma_begin=1; //första kommatecknet int comma_end=0; //sista kommantecknet int length = strlen(hsstring); //vi tar bort alla värden så som ny rad, tab etc och ersätter den med ett mellanslag for(i=0;i<length;i++) { if(hsstring[i] == '\n' || hsstring[i] == '\r' || hsstring[i] == '\t') { hsstring[i] = ' '; } } for(i=0;i<length;i++) { if(hsstring[i] == ',') { //markera vart det andra comma tecknet är comma_end = i; //varje jämt värde är ett namn if(count==0 || count==2 || count==4 || count== 6 || count==8 || count==10 || count==10|| count==12|| count==14|| count==16 || count==18|| count==20) { //kopiera texten mellan comma tecknen for(j=comma_begin;j<comma_end;j++) { //lagra spelarens namn i highscore listan test_highscore[current_player].name[j-comma_begin-1] = hsstring[j]; } current_player++; } //varje ojämt värde är poäng if(count==1 || count== 3 || count==5 || count==7 || count==9 || count==11|| count==13 || count==15 || count==17 || count==19) { //kopiera texten mellan comma tecknen for(j=comma_begin;j<comma_end;j++) { //lagra spelarens poäng i highscore listan test_highscore[current_score].score[j-comma_begin-1] = hsstring[j]; } current_score++; } comma_begin = i; count++; } } } int main(void) { CURL *curl; CURLcode res; int i =0 ; clear_highscore_table(); curl = curl_easy_init(); if(curl) { struct string s; init_string(&s); curl_easy_setopt(curl, CURLOPT_URL, "http://www.dinhemsida.se/highscore/simple_score.php"); //ange vår writefunc som skrivfunktion för CURL curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); //meddela att vi vill skriva in datan i s curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); //be curl göra allt vi bett om ovan res = curl_easy_perform(curl); //om det inte gick, så medela att vi inte kunda ansluta if(res != CURLE_OK) { printf("could not connect to website\n"); } else { //gå igenom strängen Parse_Highscore(s.ptr); //skriv ut de 10 spelarnas namn och poäng for(i=0;i<10;i++) { printf("Player:%s, Score:%s\n",test_highscore[i].name,test_highscore[i].score); } } free(s.ptr); /* always cleanup */ curl_easy_cleanup(curl); } return 0; }
Till Sist
Jag hoppas att någon får nytta av denna kod, den är inte optimal och kan säkert snyggas till en hel del, men det lämnar jag upp till dig. Syftet med denna artikel är bara att visa på ett sätt hur man kan göra det, och att försöka hålla koden något så när läsbar. Det förekommer säkert ett och annat typo i texten, men det får ni ta.
//SolarStrings, a.k.a Johan Forsblom
vBulletin-meddelande