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 


Advanced CE Tutorial: Assembly, Tracing, Debugging, and More

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials
View previous topic :: View next topic  
Author Message
h3x1c
Master Cheater
Reputation: 17

Joined: 27 Apr 2013
Posts: 306

PostPosted: Thu Jul 14, 2016 9:24 am    Post subject: Advanced CE Tutorial: Assembly, Tracing, Debugging, and More This post has 1 review(s) Reply with quote



This tutorial is aimed at those who feel comfortable completing the 9-step Cheat Engine tutorial on their own and are ready to explore new territory.

In this behemoth of a tutorial (45-minutes in length!), I use Cheat Engine with a custom Terraria script I wrote to cover a vast number of topics:

- Break and trace
- Creating a pseudorandom number generator in Assembly
- Assembly instructions like RDTSC, LEA, SHR, IDIV, and more
- Advanced scripting
- Script debugging
- Bits, nibbles, bytes, hex, etc.
- Code refactoring
- Optimization
- More that I can't think of off the top of my head Laughing

Click the image above to watch the tutorial. Enjoy! Very Happy

_________________
Back to top
View user's profile Send private message Visit poster's website
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Thu Jul 14, 2016 9:34 pm    Post subject: Reply with quote

While your calling convention is functional in this case, it is not readable, it is not maintainable, and it is certainly not good practice. Learn what the call and ret instructions are, as well as the proper calling conventions for them. If you're adamant about doing it this way, at least use a label for a return address.

When using the "dereference addresses" option in a break and trace, the values shown are before the instruction has executed. The only reason it was the same at 16:17 was because that address already had that value in it.

Your explanations involving distinctions between positive and negative numbers is flawed. With regards to any integer, if the highest bit is set, it can be interpreted in some circumstances as a negative integer. With regards to a qword, you gave the implication at 24:47 that if any bit in the upper dword is set, it's a negative number. While that is incorrect, whether the integer is negative or not is irrelevant. The only thing that matters is that the idiv instruction doesn't overflow and generate a divide error exception. More specifically, EDX cannot be above or equal to 3800 in this case.

This might be a bit pedantic, but the time stamp counter isn't random. You're relying on the time between executions of that code to be random. If you try doing this in rapid succession, use a much higher divisor, and/or call it at fixed intervals, a pattern would emerge. A more correct way of doing this would be to use rdtsc to seed a (pseudo)random number generator instead of using it as the random number itself. In this case, however, it's good enough.

shr eax,1 does not make it appear more random. You're effectively halving the precision of the timestamp counter, making this appear even less random. The effects will still be negligible to the user.

You don't need to globalalloc memory in order to reference it outside that script. All you need to do is register it as a symbol, which you've already done. Also note that the only symbols you need to register are the AoB scans- CE keeps track of the allocated memory itself.

99.7% of the data in that .CT is structures. It is encouraged in most circumstances to delete structures before you upload a .CT for this reason.


If you'd like an example using call, ret, and msvcrt.rand, I made an example random number generator a while ago. I've modified it to fit this scenario. Call getRandItem and it'll return a pseudorandom integer between 1 and 3800 inclusive. All caller-saved registers are modified, so back them up if needed.
Code:
define(randomNumber,randomGenData) // organization (only one registered symbol)
define(shouldExit,randomGenData+4)

[ENABLE]
alloc(derp,256)
alloc(getRandItem,256)
alloc(randomGenData,8)
label(mainloop)

registersymbol(randomGenData)

createthread(derp)

derp:
  rdtsc                     // read TSC into EDX:EAX
  push eax                  // push lower dword TSC onto stack
  call msvcrt.srand         // seed random number generator
  add esp,4                 // cdecl; yes cleanup
mainloop:
  push #1000                // rand number every ~1 second
  call kernel32.Sleep       // stdcall; no cleanup
  call getRandItem          // get a random item
  mov [randomNumber],eax    // move return value into [randomNumber]
  cmp [shouldExit],0        // should exit?
  je mainloop
  // cleanup and exit
  pop eax                   // pop return address of this thread
  push 8000                 // MEM_RELEASE
  push 0                    // dwSize
  push derp                 // lpAddress
  push eax                  // push return address of this thread
  jmp kernel32.VirtualFree  // jmp to VirtualFree
  // jmp instead of call so VirtualFree returns to kill this thread gracefully

getRandItem:
  call msvcrt.rand          // get random number
  xor edx,edx               // avoids divide error exception
  mov ecx,#3800             // divisor
  div ecx                   // divide EDX:EAX by ECX (#3800)
  inc edx                   // increment remainder
  mov eax,edx               // return remainder
  ret

randomNumber:
  dd 0
shouldExit:
  dd 0

[DISABLE]

// if you dealloc here, thread will execute freed memory causing a fault

shouldExit:
  dd 1  // thread takes care of dealloc and killing itself

unregistersymbol(randomGenData)

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
h3x1c
Master Cheater
Reputation: 17

Joined: 27 Apr 2013
Posts: 306

PostPosted: Thu Jul 14, 2016 10:53 pm    Post subject: Reply with quote

ParkourPenguin wrote:
While your calling convention is functional in this case, it is not readable, it is not maintainable, and it is certainly not good practice. Learn what the call and ret instructions are, as well as the proper calling conventions for them. If you're adamant about doing it this way, at least use a label for a return address.


I did what I could with the extent of my knowledge on the issue. Part of what I hate about trial-by-error learning is even when I think I've understood something, someone like you comes along and beats the shit out of it. Objectively, it's fine and I'm grateful for any/all advice, but subjectively, it pisses me off to think I've wasted time and effort on something I thought I understood well enough, and to teach at that. I thought I understood call/ret enough when attempting this all, but I certainly kept messing something up, because I couldn't get it to work, nor could I pin down my issue when trying to trace it, thus this wonky method of doing what I was trying to do.

Quote:
When using the "dereference addresses" option in a break and trace, the values shown are before the instruction has executed. The only reason it was the same at 16:17 was because that address already had that value in it.


Got it. Thanks for the heads-up.

Quote:
Your explanations involving distinctions between positive and negative numbers is flawed. With regards to any integer, if the highest bit is set, it can be interpreted in some circumstances as a negative integer. With regards to a qword, you gave the implication at 24:47 that if any bit in the upper dword is set, it's a negative number. While that is incorrect, whether the integer is negative or not is irrelevant. The only thing that matters is that the idiv instruction doesn't overflow and generate a divide error exception. More specifically, EDX cannot be above or equal to 3800 in this case.


That part at 24:47, I guess I could have done a better job clarifying, then. That's not the implication I intended. Good feedback on the negative/positive. I know in the eyes of the CPU it's just bits, but I had some issues initially trying to figure out how to get all of that working in the first place that I thought had to do with negative number errors. I guess the remainder would be whatever it was going to be regardless.

Quote:
This might be a bit pedantic, but the time stamp counter isn't random. You're relying on the time between executions of that code to be random. If you try doing this in rapid succession, use a much higher divisor, and/or call it at fixed intervals, a pattern would emerge. A more correct way of doing this would be to use rdtsc to seed a (pseudo)random number generator instead of using it as the random number itself. In this case, however, it's good enough.


I understood that, and made the distinction in the video that this was more akin to pseudorandom than actually, mathematically random.

Quote:
shr eax,1 does not make it appear more random. You're effectively halving the precision of the timestamp counter, making this appear even less random. The effects will still be negligible to the user.


I guess there's just a communication breakdown with the terminology I used. You have a fine-tuned vocabulary with terminology that I'm really just trying to fully grasp. I appreciate the experienced perspective. The end result was sufficient for what I was looking to achieve, so I was content enough at the time with what I did.

Quote:
You don't need to globalalloc memory in order to reference it outside that script. All you need to do is register it as a symbol, which you've already done. Also note that the only symbols you need to register are the AoB scans- CE keeps track of the allocated memory itself.


Yeah, I shouldn't have even said the globalalloc thing, because that's not what I meant. I was running on a different train of thought by the end of the video. It was a really out-of-context mention.

Quote:
99.7% of the data in that .CT is structures. It is encouraged in most circumstances to delete structures before you upload a .CT for this reason.


Yeah, I just figured that one out recently after wondering why the .CT was so huge. Certainly mindful of it now.

Quote:
If you'd like an example using call, ret, and msvcrt.rand, I made an example random number generator a while ago. I've modified it to fit this scenario. Call getRandItem and it'll return a pseudorandom integer between 1 and 3800 inclusive. All caller-saved registers are modified, so back them up if needed.
Code:
define(randomNumber,randomGenData) // organization (only one registered symbol)
define(shouldExit,randomGenData+4)

[ENABLE]
alloc(derp,256)
alloc(getRandItem,256)
alloc(randomGenData,8)
label(mainloop)

registersymbol(randomGenData)

createthread(derp)

derp:
  rdtsc                     // read TSC into EDX:EAX
  push eax                  // push lower dword TSC onto stack
  call msvcrt.srand         // seed random number generator
  add esp,4                 // cdecl; yes cleanup
mainloop:
  push #1000                // rand number every ~1 second
  call kernel32.Sleep       // stdcall; no cleanup
  call getRandItem          // get a random item
  mov [randomNumber],eax    // move return value into [randomNumber]
  cmp [shouldExit],0        // should exit?
  je mainloop
  // cleanup and exit
  pop eax                   // pop return address of this thread
  push 8000                 // MEM_RELEASE
  push 0                    // dwSize
  push derp                 // lpAddress
  push eax                  // push return address of this thread
  jmp kernel32.VirtualFree  // jmp to VirtualFree
  // jmp instead of call so VirtualFree returns to kill this thread gracefully

getRandItem:
  call msvcrt.rand          // get random number
  xor edx,edx               // avoids divide error exception
  mov ecx,#3800             // divisor
  div ecx                   // divide EDX:EAX by ECX (#3800)
  inc edx                   // increment remainder
  mov eax,edx               // return remainder
  ret

randomNumber:
  dd 0
shouldExit:
  dd 0

[DISABLE]

// if you dealloc here, thread will execute freed memory causing a fault

shouldExit:
  dd 1  // thread takes care of dealloc and killing itself

unregistersymbol(randomGenData)


Thanks for that example; I really appreciate it. There are a lot of gaps in my learning, some I'm aware of and others I'm not, so stuff like this is really helpful. I had absolutely no idea you could call the things you're calling in that script in AutoAssembler, so that's a huge revelation to me.

I've been looking at calling conventions and trying to understand how they all look/work. After your reply here, I honestly don't know if I'm close to grasping them or not, despite feeling like I am.

Thanks again for the apt feedback.

_________________
Back to top
View user's profile Send private message Visit poster's website
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Thu Jul 14, 2016 11:45 pm    Post subject: Reply with quote

Quote:
Part of what I hate about trial-by-error learning is even when I think I've understood something, someone like you comes along and beats the shit out of it.
It's quite clear that you do understand the fundamentals of what jmp does. In this scenario, your code works, and in the end, that's all that matters. I'm just saying there's a better way you can do this.
Quote:
I've been looking at calling conventions and trying to understand how they all look/work.
call and ret are fundamentally simple.
call pushes the address of the next instruction onto the stack and jumps to the specified address.
ret pops the value at the top of the stack off and jumps to that address.

Let's say in my example the instruction call getRandItem is stored at the address 002A102B and takes up 5 bytes (next instruction is at 002A1030). For all relevant intents and purposes, these are functionally equivalent to each other:
Code:
call getRandItem   // moves next address (002A102B+5) onto the stack and jumps to getRandItem
...

getRandItem:
...
ret                // pops the top of the stack and jumps to that address
Code:
push 002A1030      // pushes the address of the next instruction onto the stack
jmp getRandItem    // jumps to getRandItem
...

getRandItem:
...
pop edx            // pops the top of the stack into edx
jmp edx            // jumps to whatever is in edx
Code:
sub esp,4           // allocates space on the stack
mov [esp],002A1030  // moves the address of the next instruction into the stack
jmp getRandItem     // jumps to getRandItem
...

getRandItem:
...
mov edx,[esp]       // moves the value on the top of the stack into edx
add esp,4           // deallocates space from the stack
jmp edx             // jumps to whatever is in edx


Calling conventions refer to the conventions by which you call some section of assembly (subroutine aka function) to run. This includes how arguments are passed to the subroutine, which registers are used for what, and how the subroutine should return a value. Two very common calling conventions are cdecl and stdcall. What they have in common:
  • eax, ecx, and edx are caller-saved registers (i.e. caller is responsible for backing them up). Everything else is callee-saved (i.e. callee must restore them if modified).
  • Return value is in eax. Floating point numbers can be returned in ST(0) or xmm0.
  • All arguments are passed through the stack in reverse order. This means that, to the subroutine, the first argument is stored in [esp+4], the second argument is in [esp+8], etc. (assuming the callee doesn't modify the stack). If the subroutine establishes a stack frame (i.e. push ebp / mov ebp,esp), the first argument will be in [ebp+8], second [ebp+C], etc.

The only difference between the two is how they clean up arguments from the stack. cdecl expects the caller to clean them up (e.g. add esp,4 in my example), while stdcall expects the callee to clean them up (e.g. ret imm16).

My example shows off most of this. Calling cedecl functions (i.e. msvcrt.srand), calling stdcall functions (i.e. kernel32.Sleep), pushing arguments in reverse order (i.e. kernel32.VirtualFree), and even messing around with the return address to make a subroutine not return to the address of the next instruction (i.e. making VirtualFree return to the return address of the thread).

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
++METHOS
I post too much
Reputation: 92

Joined: 29 Oct 2010
Posts: 4197

PostPosted: Thu Jul 14, 2016 11:46 pm    Post subject: Reply with quote

h3x1c wrote:
Part of what I hate about trial-by-error learning is even when I think I've understood something, someone like you comes along and beats the shit out of it. Objectively, it's fine and I'm grateful for any/all advice, but subjectively, it pisses me off to think I've wasted time and effort on something I thought I understood well enough, and to teach at that.
-Don't feel that way. Everyone is at different levels. Your tutorials are valuable to someone, regardless, just as ParkourPenguin's comments are also valuable.
There are many ways to skin a cat. With what we do, if it works, it's usually good enough. But, at the same time, learning better ways and furthering our knowledge is always good. I am thankful for all contributions because if everyone kept everything to themselves, learning new things would take a lot longer.
Back to top
View user's profile Send private message
h3x1c
Master Cheater
Reputation: 17

Joined: 27 Apr 2013
Posts: 306

PostPosted: Fri Jul 15, 2016 1:40 pm    Post subject: Reply with quote

++METHOS wrote:
h3x1c wrote:
Part of what I hate about trial-by-error learning is even when I think I've understood something, someone like you comes along and beats the shit out of it. Objectively, it's fine and I'm grateful for any/all advice, but subjectively, it pisses me off to think I've wasted time and effort on something I thought I understood well enough, and to teach at that.
-Don't feel that way. Everyone is at different levels. Your tutorials are valuable to someone, regardless, just as ParkourPenguin's comments are also valuable.

There are many ways to skin a cat. With what we do, if it works, it's usually good enough. But, at the same time, learning better ways and furthering our knowledge is always good. I am thankful for all contributions because if everyone kept everything to themselves, learning new things would take a lot longer.


I agree with all that and generally feel the same way. Your last point is why I started doing CE videos in the first place. Man, I didn't know how much I didn't know when I got started, but with all the positive feedback from people who are grateful to be able to just pull up a video series and feel good about how much they learn without wasting time, that's part of what continues driving my interest. I like to educate people and share knowledge, and that in turn fuels my learning.

I was just kind of frustrated last night with that reply because it's like this: I'm a 34 year-old guy who's been around the block, and at this point in my life, I absolutely fucking hate the idea that I'm wasting my time. On anything. But ESPECIALLY with learning. And so for as much as I've struggled and fought to study and learn things on my own without asking for help because of how reluctant others are to help in the first place, it's just frustrating as fuck for someone like ParkourPenguin to come in and essentially lay to waste the result of all this time I've spent struggling, testing, learning, etc.

Let me be clear that I don't mean I'm upset with or mad at ParkourPenguin, but rather, I'm upset with reading something that was laid out in a manner that if only I had seen that earlier, or had the same thing clicked with me earlier, I could have avoided wasting so much damn time just trying to understand something.

And I get it: lots of us have done the time. We've put in all that exhaustive time and effort to learn, so why make it easy for any old person when we've had it so challenging? Even with my desire to spread knowledge, I do feel like that to an extent with some information, so I get it. But now I feel like I've been doing this stuff on and off for 3 years, and how much do I have to show for it? Nowhere near as much as I'd like.

And also, I know that a video like the one I posted is a demonstration to people like you and ParkourPenguin that I'm personally vested in learning much more than the scope of just scanning memory and changing values, so that begets much better and more informational replies, which is a good thing! Very Happy

Overall, I maintain a positive attitude about learning this stuff. First and foremost, it's a passion and something I consider fun, so even with what I consider time wasted in the process, there's likely something I enjoyed immensely in that time frame.

What I want the most is a mentor, to be honest. At this rate, I've become interested in reverse engineering as a general topic, so I've been watching stuff like Xeno Kovah's courses, etc., then trying to parlay that information and landscape of tools over to the game world, then synthesize it all in a fashion that I can make videos about for others.

Anyway, sorry to dump all this shit out for seemingly no reason, but it's a lot of stuff I've been harboring in general. The idea of optimization is appealing to me across the board: in code, in time spent learning, etc. I'm just at a point where I'm getting tired of reading eight-fucking-thousand different articles or some such just to stitch together a single coherent bit of learning--especially when it's something I find I could have learned in 10 minutes.

It's more about finding the right teacher than anything, which brings me back to why I do my videos. I try to be the teacher for others that I continuously wish I had access to in the capacity of a friend or mentor. And the CE community is great for people forthcoming with information when someone's proven they've put forth the initiative, but there are times I've needed help with something where it's been crickets, and I end up giving up on some of those things because I run out of resources and I HATE the thought of being that one nagging asshole that keeps posting questions.

People just generally aren't forthcoming publicly with many of these more advanced topics. And again, I get it, but it's just REALLY frustrating and feels like a price I continually have to pay just the same as the newbie around the corner who wants to be a proh4x so they can have some diamonds in whatever Facebook game, lol.

Alright, I'll can it for now. I just needed to brain-dump some of these thoughts. None of what I said is anything I fault anyone in this community for, and at the end of the day, if it takes me posting a video like this to get the immensely helpful feedback of someone like you or ParkourPenguin or whomever else, then that's alright. I just feel like my learning is at a level that can drastically accelerate from here, but I can't take advantage of it because I can't find the right resources/teachers/etc. to ask any given question to without falling under the scrutiny of "have you even tried this before asking".

ParkourPenguin: Thank you for that additional explanation. I was aware of the fundamental purposes of call/ret, and how they work in regards to the stack, but putting them into practice has been my Achilles heel up to this point (meaning that, in theory, I understand the use, but in practice, I still have a lot to learn).

Your examples are great; I'll really sit down with them this weekend, as well as a lot of the other things you mentioned herein. I love the idea of truly stepping into advanced script territory, making system calls, etc. I had no idea you could do that stuff. Thanks again; I really appreciate it.

_________________
Back to top
View user's profile Send private message Visit poster's website
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Fri Jul 15, 2016 5:10 pm    Post subject: Reply with quote

h3x1c wrote:
I absolutely fucking hate the idea that I'm wasting my time. On anything. But ESPECIALLY with learning.

Learning something is itself a waste if you don't put it to any use. You succeeded in creating the script, but you failed to do it by convention in a reasonably optimized manner. Regardless of whichever way you look at it, this is not a waste. People are defined by their successes just as much as their failures. What determines the significance of an action is what the person does after the fact: giving up after you fail is as much a waste as ignoring your successes. You have done neither. By uploading that tutorial, you have allowed others in your community to both use your script and learn from it. By resolving yourself to study proper calling conventions, you will learn information that you would not have if you hadn't done this in the first place. You might have been able to learn this lesson faster, but your efforts were certainly not a waste.

h3x1c wrote:
It's just frustrating as fuck for someone like ParkourPenguin to come in and essentially lay to waste the result of all this time I've spent struggling, testing, learning, etc.

I apologize for giving you that impression. I don't mean to belittle the significance of your efforts. What you have accomplished so far is far beyond what the average CE user understands, and I applaud you for your achievements and contributions to the community. By criticizing your script and offering advice, I intended to guide you to the next thing you should learn in order to improve your skills. I do not mean to berate you on your perceived inadequacies, as I'm in the same position you are. I do not know everything about computer science, but I will learn what I want to learn because it's interesting and will be useful someday.

h3x1c wrote:
We've put in all that exhaustive time and effort to learn, so why make it easy for any old person when we've had it so challenging?

That's not exactly my sentiment. I learned everything I know about computer science from trial and error, Google, and Wikipedia. Because I learned from resources that should be available to everyone else, I figure everyone else should be able to learn it as I did. If someone just doesn't get something, then they can ask their questions here, and as long as it's not something shallow or trifling (e.g. how do I hack [MMORPG]?), there are many people here who can and will help them.

h3x1c wrote:
I end up giving up on some of those things because I run out of resources and I HATE the thought of being that one nagging asshole that keeps posting questions.

So long as you show an interest in learning, you have attempted to do whatever is causing you trouble, and documentation on the topic is not readily available, there are no problems with asking as many questions as you like. Most of the time, however, the question has been asked before, information is already available, and if you try you can probably figure it out yourself (e.g. pointerscanner).

h3x1c wrote:
People just generally aren't forthcoming publicly with many of these more advanced topics.

That's because most advanced/specialized topics already have concise documentation on them that comes directly from the person(s) who invented it. For example, I can almost guarantee you anything you want to know about Intel architecture is in Intel's Software Developer Manuals. If you want to learn anything about the Windows API (e.g. GUI stuff, thread synchronization, disk management, cryptography, etc.), Microsoft has documentation on it here. There may be some topics that are not documented to the degree you may require (e.g. exception handling), so it's fine to ask about them on these forums assuming Google doesn't already have the answer for you.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
h3x1c
Master Cheater
Reputation: 17

Joined: 27 Apr 2013
Posts: 306

PostPosted: Fri Jul 15, 2016 9:52 pm    Post subject: Reply with quote

ParkourPenguin wrote:
Learning something is itself a waste if you don't put it to any use. You succeeded in creating the script, but you failed to do it by convention in a reasonably optimized manner. Regardless of whichever way you look at it, this is not a waste. People are defined by their successes just as much as their failures. What determines the significance of an action is what the person does after the fact: giving up after you fail is as much a waste as ignoring your successes. You have done neither. By uploading that tutorial, you have allowed others in your community to both use your script and learn from it. By resolving yourself to study proper calling conventions, you will learn information that you would not have if you hadn't done this in the first place. You might have been able to learn this lesson faster, but your efforts were certainly not a waste.


Yeah, I agree. My desire to continue learning is strong, even if just for helping others to learn something I struggled so much with initially. I consider that an added layer of my learning which makes me want to make sure I get it right: have I learned something well enough to be able to explain it?

Quote:
I apologize for giving you that impression. I don't mean to belittle the significance of your efforts. What you have accomplished so far is far beyond what the average CE user understands, and I applaud you for your achievements and contributions to the community. By criticizing your script and offering advice, I intended to guide you to the next thing you should learn in order to improve your skills. I do not mean to berate you on your perceived inadequacies, as I'm in the same position you are. I do not know everything about computer science, but I will learn what I want to learn because it's interesting and will be useful someday.


I appreciate the apology and encouraging words, but I really didn't want you feeling like I was having a go at YOU or like I needed to be handled with kid gloves or something. The encouragement is always nice from someone you respect (and there are a bunch of you on here who I wholly respect and am quite envious of your respective talents), and I know your feedback came from a place of being helpful.

Quote:
So long as you show an interest in learning, you have attempted to do whatever is causing you trouble, and documentation on the topic is not readily available, there are no problems with asking as many questions as you like. Most of the time, however, the question has been asked before, information is already available, and if you try you can probably figure it out yourself (e.g. pointerscanner).


I'm pretty self-sufficient for the most part, but some things are a bear, and I just don't ask questions if I don't feel like I can even articulate them well enough. The latest thing I'm stuck on is bridging the gap with dissecting Mono and finding my way to a function, instruction, or address that way instead of via scans or something like Ultimap. I feel like I'm right on the cusp of getting it, and I understand a lot of peripheral information (such as methods, a call having parameters that need to be passed, etc.). In these cases, I'm not worried about the optimal path so much as I am just trying to get whatever path I'm currently learning to work. I did create a post inquiring about this a few months ago or so, but I probably didn't word it well enough (despite trying to do so), and it received no replies. I felt like I was just spinning my wheels, so when I get to that point, I put something down and come back to it later, most likely after I've learned other things that end up being applicable.

I just feel like I'm in an odd place at the moment with learning everything--intermediate, perhaps, haphazardly finding my way to advanced. I've enjoyed being able to come here and learn from people like you, though, so...again, I thoroughly appreciate your (and others') guidance and contributions. I hope none of this came off as though I was upset with you personally or whatever. It's nothing but respect and appreciation from my end!

_________________
Back to top
View user's profile Send private message Visit poster's website
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Fri Jul 15, 2016 10:15 pm    Post subject: Reply with quote

I've never bothered looking into CE's mono features that much. I may use it to get a higher-level overview of how the game works and I definitely use it for dissecting structures, but beyond that, I'll just do whatever I want in pure asm.

Look through monoscript.lua for information on pretty much everything you can do and how everything works. It's not well documented and doesn't explain the underlying concepts, but it's good enough. Going through forum posts (e.g. this topic) can help as well if you Google everything you aren't certain of.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials 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