Asm.Net is an assembly emulator which is developed in C# which will also help you develop your programs using assembler language in the .NET Framework. You will also be able to run programs using Asm.Net for emulating programs.
Introduction
ASM.Net is an assembly x86 emulator which can emulate the instructions of assembly. Not all of them yet though. Yet there are a lot of instructions/opcodes which are already working. And may be enough for you to work in it.
ASM.Net is also able to convert all the code you write to a byte array which ASM.Net can read again to get all instructions/variables/APIs. So the code you write in ASM.Net is all portable and can be ran in another computer or processed or whereever you want without any problems. But this is not all, the byte array ASM.Net is able to generate is encrypted at every section and compressed to keep it away from thieves for your code.
Using the code
Using the code in ASM.Net is easy but you really need to have some knowledge about assembly to understand any of it, e.g., JMP, JNZ, CALL, XOR and so on... With the OpcodeWriter we can write our code, create variables, and do more. At the end when we write everything that the program needs to do we can also debug it using the ASM.Net debugger and see if everything is working like expected.
This is an example code for how to write our MessageBox:
OpcodeWriter writer = new OpcodeWriter();
writer.codeSection.PUSH_VALUE(0); writer.codeSection.PUSH_STRING("Title here");
writer.codeSection.PUSH_STRING("Hello CodeProject!");
writer.codeSection.PUSH_VALUE(0); writer.codeSection.CALL(Functions.User32_MessageBoxA); AsmNet asmNet = new AsmNet(writer.Generate(true)); Processor Cpu = asmNet.InitializeCPU(); Cpu.RunLoop();
As you can see it's not that much code to show a MessageBox. And as may have noticed ASM.Net only needs one argument which is the byte array I told you about. The OpcodeWriter
is able to convert to a byte array using the Generate
function. The True
you see as argument for the Generate
function is to check every JUMP
address for errors at runtime. This could prevent errors at runtime before you would share it with others.
But showing a simple MessageBox is not all ASM.Net can do, it can do a lot more. This is a simple TCP server:
OpcodeWriter writer = new OpcodeWriter();
WSAData wsaData = new WSAData();
sockaddr_in sockaddr = new sockaddr_in();
sockaddr_in Clientsockaddr = new sockaddr_in();
VirtualAddress wsaDataAddr = writer.dataSection.CreateVariable(wsaData);
VirtualAddress SockinAddress = writer.dataSection.CreateVariable(sockaddr);
VirtualAddress ClientSockinAddress = writer.dataSection.CreateVariable(Clientsockaddr);
VirtualAddress ArrayAddress =
writer.dataSection.CreateVariable(ASCIIEncoding.ASCII.GetBytes(":)"));
writer.codeSection.MOV_VARIABLE_VALUE(wsaDataAddr, "HighVersion", (ushort)2);
writer.codeSection.MOV_VARIABLE_VALUE(wsaDataAddr, "Version", (ushort)2);
writer.codeSection.MOV_VARIABLE_VALUE(SockinAddress,
"sin_family", (short)ValueCodes.InterNetworkv4);
writer.codeSection.PUSH_VALUE(1337); writer.codeSection.CALL(Functions.ws2_32_htons);
writer.codeSection.MOV_VARIABLE_REGISTER(SockinAddress, "sin_port", Register.EAX);
writer.codeSection.PUSH_VARIABLE(wsaDataAddr);
writer.codeSection.PUSH_VALUE(36);
writer.codeSection.CALL(Functions.ws2_32_WSAStartup);
writer.codeSection.MOV_ECX(0);
writer.codeSection.CMP(CmpRegisterOpcodes.CMP_ECX_EAX);
writer.codeSection.JNE("failed");
writer.codeSection.PUSH_VALUE(ValueCodes.Tcp, (int)0);
writer.codeSection.PUSH_VALUE(ValueCodes.Stream, (int)0);
writer.codeSection.PUSH_VALUE(ValueCodes.InterNetworkv4, (int)0);
writer.codeSection.CALL(Functions.ws2_32_socket);
writer.codeSection.MOV_ECX((int)ValueCodes.INVALID_SOCKET);
writer.codeSection.CMP(CmpRegisterOpcodes.CMP_ECX_EAX);
writer.codeSection.JE("failed");
writer.codeSection.MOV(MovRegisterOpcodes.MOV_EBX_EAX);
writer.codeSection.PUSH_VALUE(Marshal.SizeOf(sockaddr));
writer.codeSection.PUSH_VARIABLE(SockinAddress); writer.codeSection.PUSH_EBX(); writer.codeSection.CALL(Functions.ws2_32_bind);
writer.codeSection.PUSH_VALUE((int)100);
writer.codeSection.PUSH_EBX(); writer.codeSection.CALL(Functions.ws2_32_listen);
writer.codeSection.PUSH_VALUE(-11); writer.codeSection.CALL(Functions.Kernel32_GetStdHandle);
writer.codeSection.MOV(MovRegisterOpcodes.MOV_EDX_EAX);
writer.codeSection.CreateLabel("loop");
writer.codeSection.PUSH_VALUE(Marshal.SizeOf(Clientsockaddr));
writer.codeSection.PUSH_VARIABLE(ClientSockinAddress);
writer.codeSection.PUSH_EBX(); writer.codeSection.CALL(Functions.ws2_32_accept);
writer.codeSection.MOV(MovRegisterOpcodes.MOV_EDI_EAX);
writer.codeSection.PUSH_VALUE(0);
writer.codeSection.PUSH_VALUE(0);
writer.codeSection.PUSH_VALUE(20);writer.codeSection.PUSH_STRING("new client accepted\r\n");
writer.codeSection.PUSH_EDX();
writer.codeSection.CALL(Functions.Kernel32_WriteConsoleA);
writer.codeSection.PUSH_VALUE(0);
writer.codeSection.PUSH_VALUE(2);
writer.codeSection.PUSH_VARIABLE(ArrayAddress);
writer.codeSection.PUSH_EDI(); writer.codeSection.CALL(Functions.ws2_32_send);
writer.codeSection.PUSH_EDI();
writer.codeSection.CALL(Functions.ws2_32_closesocket);
writer.codeSection.JMP("loop");
writer.codeSection.PUSH_EBX();
writer.codeSection.CALL(Functions.ws2_32_closesocket);
writer.codeSection.CreateLabel("failed");
writer.codeSection.XOR(XorRegisterOpcodes.XOR_ECX_ECX);
When you are reading through the code, you will find some JUMPs, Calls etc. But this example is for starting a simple TCP server which accepts connections and sends a simple smiley face " " align="top" src="http://www.codeproject.com/script/Forums/Images/smiley_smile.gif" /> " to the one who connects. As you can see here in this image it's waiting for a new connection. By the way don't think it's Linux it's just Windows 7 with an Ubuntu theme:
OK, so let's do for example in our command line of Windows "telnet 127.0.0.1 1337":
As you can see when I pressed Enter in the command line it came up with a smiley face:
As you could see the " " align="top" src="http://www.codeproject.com/script/Forums/Images/smiley_smile.gif" /> " came up and it worked just fine and something to another console was written that a new connection was accepted (look above for the code in the TCP server). And to make debugging a little more easier let's see where our JUMPs are going:
As you can see the red line shows us instantly where the JUMP is going to. If there are any questions I'd love to answer those. But you also should need to dig in the code a little. There are also events etc., that you can use.
Points of Interest
While making ASM.Net I needed to laugh a little because I can now write portable code instead of using CodeDom which can give errors because a .dll is missing whatsoever and dumps its code to a temp directory that people can access and steal the code from.
And ASM.Net can run anywhere but it still needs the ASM.Net library and don't even need to be dumped to the hard drive if not needed.
History
You can checkout our SVN: