Sunday 4 May 2014

[GMS] Modify WP8 to add another Ad Network

Hi guys

This post is kind of a “dev diary” in which I want to share some possible methods to add another ad network to WP8 game made by Game Maker Studio.

 I tried to recall as many details as possible, since I did it about a month ago. Besides, the trial license for my Reflector has expired, so, the name of some features mentioned here could be incorrect.

Now, enjoy the post :)I hope you like it.


First, I really don’t know much about coding.

I took this stuff just because a friend of mine keeps asking me if there’s a way to make Game Maker Studio to include another advertising network besides the sucking Microsoft PubCenter.

He has a point, since that network gets complaints from devs due to poor revenue and few of supporting countries.

Yeah, at that time I got nothing to do, and had no idea for my new game ( I had one now :) )

So, challenge accepted !

To begin with, I assume that you’ve already know how to add ad into every app.

So, if you make app for, say, Android or iOS platform, there’re choices for you : Admob, iAd, etc,not so many, but acceptable.

But, tell me, have you ever wanted to include another ad network besides the available choices ? For example, InMobi or Smaato ?

It’s a lot easier if you know how to code your game using Visual Studio or Eclipse or Xcode, but if you do, then you don’t have to use Game Maker Studio, right ? :D

So, my friend shows me that, if I can succeed, there’re two things that I can accomplish :
  • Add another ad network to WP8 app.
  • Add any ad network to any app I like ( SWEET ! )
Therefore, although I know just a thing or two about coding, I decided it’s worth a try.

Part 1 : The main one is inside a DLL


So, I sit and brainstormed to find a way to solve the problem, there’re two obvious ones :

  • Use an extension in Game Maker Studio
Yeah, YoyoGame shows no tutorial about this so far, I searched Google and find a good one here.
Bad news is, we can’t use extensions for WP8 app ( arggg…. ).

  • Analyze the whole app, see if we can modify the code somehow.
I hope there could be another way, but, grin and bear it. It’s the hardest way, but focuses on the problem directly.

So, in order to do that, you have to prepare something (  I use my friend’s PC, they are all there )

  • 7-Zip : to add file to .xap file
  • Visual Studio 2012 : so that you can read the code
  • Windows 8.1 installed :
  • Decompiling tool : JetBrains dotPeek ( Free ) and Reflector ( 14-day trial )
  • A plugin for Reflector : Reflexil, tiny but powerful plugin to modify the DLL file
  • A XAP file of your game

OK, here we go.

*Note* : This is just an experiment, so do it at your own risk. I recommend you to save your app before doing this.

Decompile the XAP file

It’s a piece of cake, since a xap file is just a type of ZIP file.

You can rename the file extensions to ZIP and extract it to a folder.

There’re many things here ( scary ! ), but pay attention to a DLL file that has something  like“WinPhoneRunnerAppInterop”, that’s our target.

All of our necessary files are included in this file, so you should find a way to read it.

Open dotPeek, navigate to that DLL file, there’re many stuff here that could make you dizzy ( Me too ! )

I target the file called MainPage.

Code, code everywhere

This is it ! The one that controls every manner in Game Maker Studio app.

Next step is to decompile it into a project and start adding stuff.

If you’re using dotPeek, right click the DLL file, and choose Export to Project

Tick all the options, and choose a destination folder, and it’s done.

What do we have here  ? A nice project, ready to be modified and executed.


It looks that I could win the bet, but the nightmare has just begun.

Part 2 : Decompile and Recompile, the craziest thing in the world

Now I had a lot of stuff here at Visual Studio 2012, the next logical thing is to rebuild the file

When I pressed that sexy green button, a console popped up and said “ Errors” ( Coders, you may be SO familiar with it :)

Basically, I forgot to add the missing reference to the project, where it should be.

OK, using JetBrains, I could find out the missing files and finally reduced the error message to only 1. Yay !

But, I still couldn’t build that DLL, due to the fact that the missing file, which caused the remaining error, is solved if I used the latest version of Windows.winmd file. But, if I used this very file, the error increased to 14 !

Oh my !

After trying three or four times to rebuild the file, I decided that it isn’t worthwhile.

When I used .NET Reflector, it turned out that the Windows.winmd file used in Game Maker Studio is a home-brewed one.

Yes, YoyoGames didn’t use a standard file to build the game. Good job, YoyoGames !

Did I tell you that I also used .NET Reflector to decompile and recompile ? Yeah, any sane man can stop right now and do other stuff. Unfortunately, I was too stubborn to accept that fact.

After consulting two professors about this field ,who also warned me that it could be useless, well, you know, I didn’t care, I still got no advice from them.

Okay, after doing some nice searches on Google, I found out .NET Reflector and its plugin, Reflexil, and a nice, detailed tutorial video from the Reflexil’s creator himself. Thank you so much Sébastien, you rock.

You can see it here :

 https://www.youtube.com/watch?v=XaWtoCmOGpw

Basically, .NET Reflector did the same as JetBrains, but with Reflexil plugin, you can analyze any .EXE or .DLL file, modify it and recompile again, without having to export to project.

Furthermore, Reflexil can find reference for you as long as you installed it. Love it !

It can also “inject” method, reference to .EXE or .DLL file without opening the code. I really appreciate this feature.

You can modify the code manually using Reflexil as well, you see, this tool is very powerful.

Next part, I’ll show you how modified the DLL file.

Part 3 : Now I have the magic wand ready.


Yeah,that’s what I thought when I watched that clip by Sebastien.


As I said earlier, you can modify the code manually using Reflexil. To do that, in the Reflector, go to Tools, and click Reflexil.

Drag and Drop that .DLL into the Reflector console, it will analyze the file and come up with all the content.
Now you need to go to the Main Page.cs file

Take a look at the content, remember that :

  • The .ctor() is the constructor
  • Those with pink squares are Methods
  • Those with Blue Squares are Variables.

That’s the basics for now, you ‘ll find out when playing with this tool.

OK, here’re the steps I took :

I tried to use Vserv, before using it, we must add the DLL ( or Reference )

  • First, right click on the MainPage, and choose “Inject Reference”, I type exactly “vservWindowsPhone” in the Name field of popup.
  • Copy the vservWindowsPhone.dll to the working folder.
  • Reflexil asked me to save ( whenever you “inject” something o the original file, remember to save)
    Saved and load the file back.
  • Find the reference (vservWindowsPhone) and click on it, if Reflexil can find the .DLL, it’ll display the content, otherwise, it’ll ask you to provide that path to that file.
  • OK, now I finished adding the vservWindowsPhone.dll

Now, after injecting that DLL, theoretically,I can modify the MainPage to display Vserv add, but NO, I opened the file, took a look, and pressed “Compile” but another error appears.

So, I stuck here, right ? No, after playing with Reflexil for a while, I noticed something interesting :

When you open a DLL or a code, Reflector displays its content (the code ).

But Reflexil always displays the same thing, but in other format with some strange operator  like “ltdstr”, “nop” or similar things. I think that it’s intermediate language ( IL )

Then, if I can’t type code directly and compile it, how about taking a longer route : Adding the operator, line by line.

This method has one strong point :

Reflexil will modifies the content without going through the compiling process, which means that I can modify the file as much as I wish, and don’t care about the issue with compiling.

But it has one weak point : The IL looks more terrible than the code, and I don’t want to spend another 2 days learning through trials and errors.

The solution is simple : Build a XAP file with Vserv Ad, decompile it, and retype the IL .

YEAH !

Build a XAP file is way too easy for me now, so I can come up with the IL with no problem.

Here is the code for displaying Vserv Ad, in XAP file :

public class MainPage : PhoneApplicationPage
  {
    private Direct3DBackground m_d3dBackground;
        internal DrawingSurfaceBackgroundGrid DrawingSurfaceBackground;
    private bool _contentLoaded;

    public MainPage()
    {
      this.InitializeComponent();
      public VservAdControl VMB;
      VservAdControl instance = VservAdControl.Instance;
      instance.SetRequestTimeOut((ushort) 30);
      instance.DisplayAd("8063", (Grid) this.DrawingSurfaceBackground);
      instance.VservAdClosed += new EventHandler(this.VACCallback_OnVservAdClosing);
      instance.VservAdError += new EventHandler(this.VACCallback_OnVservAdNetworkError);
      instance.VservAdNoFill += new EventHandler(this.VACCallback_OnVservAdNoFill);
    }

    private void VACCallback_OnVservAdClosing(object sender, EventArgs e)
    {
      int num = (int) MessageBox.Show("Ad Closed by user", "Interstitial Ad", MessageBoxButton.OKCancel);
    }

    private void VACCallback_OnVservAdNetworkError(object sender, EventArgs e)
    {
      int num = (int) MessageBox.Show("Data connection not available", "No Data", MessageBoxButton.OKCancel);
    }

    private void VACCallback_OnVservAdNoFill(object sender, EventArgs e)
    {
      int num = (int) MessageBox.Show("No Ad Available", "No Fill", MessageBoxButton.OKCancel);

    }
If you open this file in Reflexil, the IL is :




16
call
System.Void PhoneDirect3DXamlAppInterop.MainPage::InitializeComponent()
21
nop

22
ldarg.0

23
call
vservWindowsPhone.VservAdControl vservWindowsPhone.VservAdControl::get_Instance()
28
stfld
vservWindowsPhone.VservAdControl PhoneDirect3DXamlAppInterop.MainPage::VMB
33
ldarg.0

34
ldfld
vservWindowsPhone.VservAdControl PhoneDirect3DXamlAppInterop.MainPage::VMB
39
ldc.i4.s
30
41
callvirt
System.Void vservWindowsPhone.VservAdControl::SetRequestTimeOut(System.UInt16)
46
nop

47
ldarg.0

48
ldfld
vservWindowsPhone.VservAdControl PhoneDirect3DXamlAppInterop.MainPage::VMB
53
ldstr
8063
58
ldarg.0

59
ldfld
System.Windows.Controls.DrawingSurfaceBackgroundGrid PhoneDirect3DXamlAppInterop.MainPage::DrawingSurfaceBackground
64
callvirt
System.Void vservWindowsPhone.VservAdControl::DisplayAd(System.String,System.Windows.Controls.Grid)



69
nop




70
ldarg.0

71
ldfld
vservWindowsPhone.VservAdControl PhoneDirect3DXamlAppInterop.MainPage::VMB
76
ldarg.0

77
ldftn
System.Void PhoneDirect3DXamlAppInterop.MainPage::VACCallback_OnVservAdClosing(System.Object,System.EventArgs)
83
newobj
System.Void System.EventHandler::.ctor(System.Object,System.IntPtr)
88
callvirt
System.Void vservWindowsPhone.VservAdControl::add_VservAdClosed(System.EventHandler)
93
nop

69
nop




94
ldarg.0

95
ldfld
vservWindowsPhone.VservAdControl PhoneDirect3DXamlAppInterop.MainPage::VMB
100
ldarg.0

101
ldftn
System.Void PhoneDirect3DXamlAppInterop.MainPage::VACCallback_OnVservAdNetworkError(System.Object,System.EventArgs)
107
newobj
System.Void System.EventHandler::.ctor(System.Object,System.IntPtr)
112
callvirt
System.Void vservWindowsPhone.VservAdControl::add_VservAdError(System.EventHandler)
117
nop




118
ldarg.0

119
ldfld
vservWindowsPhone.VservAdControl PhoneDirect3DXamlAppInterop.MainPage::VMB
124
ldarg.0

125
ldftn
System.Void PhoneDirect3DXamlAppInterop.MainPage::VACCallback_OnVservAdNoFill(System.Object,System.EventArgs)
131
newobj
System.Void System.EventHandler::.ctor(System.Object,System.IntPtr)
136
callvirt
System.Void vservWindowsPhone.VservAdControl::add_VservAdNoFill(System.EventHandler)
141
nop

142
nop

143
ret



Now, the last part is easy, open both the sample XAP file with Ad, and my game in Reflector.
 Use Reflexil and start copying.

The process is as follow
  • Open Reflector
  • Open Reflexil
  • Right Click the item ( object, class ) you want to add the method
  • Type the name of the method
  • Save and open again
  • Go to tab Parameter in Reflexil and add parameter if you want
Now for the body of the method, or add more content to it
  • Go to the item
  • Go to the Instructions tab
  • Right click and choose "Add new"
  • Add "nop" operator as many as possible, as long as it fits what you want to have in the method
  • Save and load the DLL
  • Now you can add the IL to the file, replace the "nop" operator

Important
  • Before adding the content to the original method , or injecting method to a class, to avoid errors, I find it’s a good idea to add a lot of “nop” operator into the body of the target, then save, load it again and replace the nop with your desired IL. 
  • To avoid interfering with the original code, it’s the best idea to start from above the end  ( above the “ret” operator )

So, after 1 hour of copying, retyping and adding, I came up with a really nice modified DLL.

To make it easier, I modified the InitAd() method which is available in the constructor of the game made by Game Maker Studio.

Finally, open the xap file and overwrite the original DLL. I backed up the original DLL file
Now, it’s time to test the result

The Result is … NOT WORKING

I don’t know the reason why, but the game crashes every time with the modified DLL, but it works well with the original DLL.

It looks like GMS has some kinds of protection against modifying or adding content to the DLL. The Size Checker, maybe ? Because the DLL’size will obviously larger than the original one.

Well, at this time, I gave it back to you, because it’s beyond my knowledge now. But hence, now I know how to modify a DLL with the combo Reflector and Reflexil. Not bad, eh ?

I’ll look for more solutions to make GMS XAP file to work with other ad network

See ya !

No comments:

Post a Comment