Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


C Programming question

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
tanjiajun_34
Grandmaster Cheater
Reputation: 0

Joined: 16 Feb 2006
Posts: 786
Location: Singapore

PostPosted: Tue Oct 19, 2010 8:45 am    Post subject: C Programming question Reply with quote

I just started it so sorry if I ask way too stupid question.
I just want it to compare if the inputted text is "testing", if it is it will show the "YEAH!". But it just did not show when I type "testing".

Code:
#include <stdio.h>
void main()
{
   int i;
   char str[30];
   while (i<10000)
   {      
   scanf("%s",str);
   if (str=="testing")
   {
      printf("YEAH!");
   }
   }
}
Back to top
View user's profile Send private message
Slugsnack
Grandmaster Cheater Supreme
Reputation: 71

Joined: 24 Jan 2007
Posts: 1857

PostPosted: Tue Oct 19, 2010 9:02 am    Post subject: This post has 1 review(s) Reply with quote

In C, strings can not be compared directly. The x86 instruction set only allows direct comparison of byte/word/dword values. Since your string is 8 bytes ( including null terminator ) you will have to use a string comparison algorithm.

There are plenty out there, the most common one being strcmp(). Or even better if you are doing Windows programming _tscmp().
Back to top
View user's profile Send private message
KernelMode
How do I cheat?
Reputation: 1

Joined: 13 Oct 2010
Posts: 9
Location: Messing around with bits in you kernel for now...

PostPosted: Tue Oct 19, 2010 11:40 am    Post subject: Reply with quote

Yes like Slugsnack said you can't just compare all the bytes of something at once. It's just how it works, its not just with strings. On 32-bit, a DWORD/4 bytes/32-bit value is the largest amount of data that can be read or written in a single instruction. On 64-bit, the largest is you guessed it, 8 bytes/64-bits.

For example, to copy some memory from one place to another, we can't just say tada! and the memory is copied. No... Instead the memory is moved say a dword at a time until all memory we wanted is copied. Little small operations on bytes, words, and double words, repeated many times form bigger, more complex operations.

A function like strcmp() goes though and compares each byte of the first string to each byte of the second string, and returns 0 if they are equal. _stricmp() for case insensitive searches.

so...

Code:

if(strcmp(str, "testing") == 0)
{
        printf("YEAH!");
}


We can make our own simple string comparison functions to better understand whats going on... Note: For my string compare functions below I return 1 if they are the same and 0 if they are not, which is unlike the normal string comparison functions.

Case-sensitive compare:
Code:

int StringComp(char *FirstString, char *SecondString)
{
   int i = 0;
   while(FirstString[i] != 0) //while we haven't reached the end of the first string
   {
      if(FirstString[i] != SecondString[i]) //if current byte of first string doesn't equal current byte of second
         return 0;

      i++;
   }

   //if we made it here, past the while loop, then...
   //the second string is the same as the first string for as long as the first string is...
   //if the second string is longer, but all characters have been the same up to the last character of the first string
   //well thats what the next line is for ;)

   if(SecondString[i] == 0) //second string is at the end as well so its a match
      return 1;
   else
      return 0;
}


Case-insensitive compare:
Code:

int StringIComp(char *FirstString, char *SecondString)
{
   int i = 0;
   char singlecharacter, switchcaseletter;
   while(FirstString[i] != 0)
   {
      singlecharacter = SecondString[i];
      
      //this translates to english as..."If singlecharacter is an uppercase alphabetical character or if singlecharacter is a lowercase alphabetical character"
      if(singlecharacter >= 0x41 && singlecharacter <= 0x5A || singlecharacter >= 0x61 && singlecharacter <= 0x7A)
      {
         switchcaseletter = singlecharacter ^ 0x20; //xor'ing a letter with 0x20 switches the letter from uppercase to lowercase/vice versa

         if(FirstString[i] != singlecharacter && FirstString[i] != switchcaseletter)
            return 0;
      }
      else
      {
         //character is not alphabetical so don't inverse the case (since it's not a letter of the alphabet, that will screw it up)
         if(FirstString[i] !=  singlecharacter)
            return 0;
      }

      i++;
   }
         
   if(SecondString[i] == 0) //second string is at the end as well so its a match
      return 1;
   else
      return 0;
}


Usage:
Code:


char *str = "Hello World!";

if(StringComp(str, "Hello World!") == 1)
{
//a match
}

if(StringIComp(str, "hEllO wOrLd!") == 1)
{
//a match
}



It's probably best to stick with using the string compare's your given... This was just meant for educational purposes...

However if you ever needed your string comparison to be faster, and you've debugged your program and found it to be slow, some custom written assembler string comparison functions just might speed it up a bit Smile Not that those are assembler (clearly they are C++ written) but could easily be made into assembler (Given that you know assembler of course).
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
Slugsnack
Grandmaster Cheater Supreme
Reputation: 71

Joined: 24 Jan 2007
Posts: 1857

PostPosted: Tue Oct 19, 2010 12:42 pm    Post subject: Reply with quote

Another thing. You are making a conceptual error by comparing str to a string. str is not a string. str is simply a pointer. It just so happens that it points to a set of bytes representing a string. If the value you want to check is 4 bytes or less it is actually possible to compare by value instead of using an algorithm.
Back to top
View user's profile Send private message
hcavolsdsadgadsg
I'm a spammer
Reputation: 26

Joined: 11 Jun 2007
Posts: 5801

PostPosted: Tue Oct 19, 2010 1:53 pm    Post subject: Reply with quote

KernelMode wrote:
Yes like Slugsnack said you can't just compare all the bytes of something at once. It's just how it works, its not just with strings. On 32-bit, a DWORD/4 bytes/32-bit value is the largest amount of data that can be read or written in a single instruction. On 64-bit, the largest is you guessed it, 8 bytes/64-bits.


what about SSE?

movaps is a single instruction :V
Back to top
View user's profile Send private message
KernelMode
How do I cheat?
Reputation: 1

Joined: 13 Oct 2010
Posts: 9
Location: Messing around with bits in you kernel for now...

PostPosted: Tue Oct 19, 2010 4:57 pm    Post subject: Reply with quote

slovach wrote:
KernelMode wrote:
Yes like Slugsnack said you can't just compare all the bytes of something at once. It's just how it works, its not just with strings. On 32-bit, a DWORD/4 bytes/32-bit value is the largest amount of data that can be read or written in a single instruction. On 64-bit, the largest is you guessed it, 8 bytes/64-bits.


what about SSE?

movaps is a single instruction :V


Ah yes, the xmm registers and accompanying instructions. I was forgetting about those. So I think my statement is wrong. Maybe I should change it to "On a 32-bit OS, 32-bits/4 bytes is the largest size of data that can be read or written at one time."

Getting rid of the "in a single instruction" part should make it technically correct.

However it still may be wrong... It all depends on how those instructions that deal with more than 32-bits conduct their business. Do they actually do their magic in one swift operation? Or do the instructions themselves do a few mini operations to achieve the result? It gets more confusing the more I think about it, but I would just like to be clear about this.

Well whether my new statement is correct or not, we can't deny the inherent limitation of 32-bit!

I've never used the movaps or movups instructions before, but I attempted messing around with it and CE just now. For some reason I couldn't get it to assemble any instruction that would movaps/movups from an xmm register back into my memory location. (I may have discovered a bug in CE) even adding an 'xmmword ptr' keyword doesn't seem to help. I don't think CE even recognizes that keyword as "movups xmm0,[eax]" failed to assemble also when adding it like "movups xmm0, xmmword ptr [eax]"

Code:

alloc(InstructionTest, 128)
alloc(OneTwentyEightBits, 16)
registersymbol(OneTwentyEightBits)

OneTwentyEightBits:
dd 00000001
dd 00000002
dd 00000003
dd 00000004

InstructionTest:
lea eax,[OneTwentyEightBits]
xorps xmm0,xmm0 //clear xmm0 register
movups xmm0,[eax] //mov four 32-bit values in one instruction
//xmm0 currently: 00000001 - 00000002 - 00000003 - 00000004
shufps xmm0,xmm0,93 //after: 00000004 - 00000001 - 00000002 - 00000003
shufps xmm0,xmm0,93 //after: 00000003 - 00000004 - 00000001 - 00000002
shufps xmm0,xmm0,93 //after: 00000002 - 00000003 - 00000004 - 00000001
shufps xmm0,xmm0,93 //after: back where we started
//xmm0 currently: 00000001 - 00000002 - 00000003 - 00000004
//movups [eax],xmm0  //for some reason this wont assemble
ret


Since I couldn't get that instruction to compile (thats what I was going to use to see changes) I instead neglected adding a createthread line and just injected and set a breakpoint and manually created the thread. That let me see the values in the xmm0 register, but all in all what good is this if I can't get the value back out of the register! Razz I think doing a db to define the bytes of the instruction would probably work, but CE should really be able to assemble it!


EDIT: As it seems it is actually a bug, a workaround as Dark Byte described is to use the same first instruction then manually change the second byte of it before it executes. You can either edit the byte manually by hand or I chose to put it in the script. By adding a label 'MoveBackInst' right above the instruction, I avoided having to count the bytes leading up to it. I find it better that way as any code added/removed from between the two movups instructions wont effect anything and I wont have to be recounting bytes after each change.

Code:

alloc(InstructionTest, 64)
alloc(OneTwentyEightBits, 16)
registersymbol(OneTwentyEightBits)
label(MoveBackInst)

OneTwentyEightBits:
dd 00000001
dd 00000002
dd 00000003
dd 00000004

InstructionTest:
mov byte ptr [MoveBackInst+1],11
lea eax,[OneTwentyEightBits]
xorps xmm0,xmm0 //clear xmm0 register
movups xmm0,[eax]
shufps xmm0,xmm0,93
shufps xmm0,xmm0,93
shufps xmm0,xmm0,93
shufps xmm0,xmm0,93
MoveBackInst:
movups xmm0,[eax]
ret




Workaround.png
 Description:
After first instruction is executed the instruction of interest is modified.
 Filesize:  59.39 KB
 Viewed:  17702 Time(s)

Workaround.png




Last edited by KernelMode on Wed Oct 20, 2010 5:09 am; edited 1 time in total
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
hcavolsdsadgadsg
I'm a spammer
Reputation: 26

Joined: 11 Jun 2007
Posts: 5801

PostPosted: Tue Oct 19, 2010 6:40 pm    Post subject: Reply with quote

packed instructions are effectively done in one shot.
Back to top
View user's profile Send private message
Slugsnack
Grandmaster Cheater Supreme
Reputation: 71

Joined: 24 Jan 2007
Posts: 1857

PostPosted: Tue Oct 19, 2010 6:56 pm    Post subject: Reply with quote

KernelMode: The x86 instruction set is sort of screwed up and very inconsistent. It is neither RISC nor CISC, it is some weird mixture of both. The other inconsistencies of x86 make it an architectural nightmare. For this reason, it is not all that useful to care the definition when you speak of 'one instruction' in this context. For even more confusion and inconsistency look into 'macro instructions' such as scasb/w/d or random instructions like jecxz, etc.

To answer your question:
Quote:
Do they actually do their magic in one swift operation?


It completely depends on your definition of an 'operation'. Do you mean one cycle ? Are you bearing in mind pipelining ?
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 458

Joined: 09 May 2003
Posts: 25302
Location: The netherlands

PostPosted: Tue Oct 19, 2010 7:36 pm    Post subject: Reply with quote

Looks like a bug in ce 5.6.1

anyhow, use the movups xmm,[address] and then change the second byte from 10 to 11 for the reverse operation

e.g:
movups xmm1,[rax]=0f 10 08
so
movups [rax],xmm1=0f 11 08

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
KernelMode
How do I cheat?
Reputation: 1

Joined: 13 Oct 2010
Posts: 9
Location: Messing around with bits in you kernel for now...

PostPosted: Wed Oct 20, 2010 5:40 am    Post subject: Reply with quote

Thanks Dark Byte! Using the same instruction then modifying the one byte does the trick!

Slugsnack: You're right its better to not care too much in the technical details of it. It is what is it is I guess! Wink

In case anyone else wanted to play around with the movaps/movups instructions and didn't get what Dark Byte means, I edited my post above to show an example.
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites