Requires knowledge of the target OS. You can learn about 90% of a executables intended purpose by looking at the import tables. This is where you see the ASCII naming DLLs and Win32 functions. It's defined in the PE format. It's questionable when you have a very small executable with no version information with the bulk of its imports having to do with registry, file, keyboard, and network functions and little else.
I tend to start from a system or API call performing a specific suspicious act I'm interested in, such as sending data via a winsock call, and work backwards to see where the parameters came from and how the data is formed. If you start top down at the executables entry point you could waste hours stepping your way through the C runtime stub and WinMain and get lost quickly when staring at raw assembly doing mundane and routine stuff like setting up the heap, etc.
Don't try to decode the assembly top to bottom and fully reverse engineer the program to C source. It's not going to happen. Instead look at API calls and determine what the program is trying to do at the highest level. You don't need to reverse engineer 1000 prologues/epilogues and determine function names, most of which will be standard C runtime functions anyway and a waste of time, just to see that a program is hooking the keyboard, creating a file, and dumping its contents to a network socket.
They key is to start in the middle and follow and back trace from places where well known and defined API calls are being made. With a quality debugger you can associate jumps into the import table with ASCII Win32 API function labels to make it easier on your eyes. The language of reverse engineering is not assembly language, it's API, because ultimately in order to do anything outside it's own virtual sand box, every program will have to call API functions to interact with the outside world. Flow charting the API calls will be 1000 times more productive than staring at x86 opcodes. After you've learned the general framework based on the API calls and have an idea what the program is doing and what you are looking for, you can be more specific and start sifting in between the API calls to the assembly and see how parameter data is formed, what data is being passed and where its coming from or how its being calculated, etc.
It's the same idea as writing a good console emulator. Why bother with thousands upon thousands of instructions emulating the hardware when all you have to do is write a wrapper for "draw_triangle" that passes it along to Direct3d?
You already have the leg up by suspecting that it's malicious. You already know what to look for and what to expect to see.