Thread: JBPatch
View Single Post
Old 05-10-2012, 07:49 PM   #63
ixtab
(offline)
ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.ixtab ought to be getting tired of karma fortunes by now.
 
ixtab's Avatar
 
Posts: 2,907
Karma: 6736092
Join Date: Dec 2011
Device: K3, K4, K5, KPW, KPW2
UPDATE: Please download the updated version.


Here's another HOWTO for writing a patch.

Important Notes:
  • This is intended for KSO devices. I don't know what it will do on non-KSO Kindles. Probably nothing, or at least nothing bad, though.
  • If you're not interested in the howto, but only in the patch itself, scroll down, but read the bold parts.
  • Don't start a discussion about whether this is ethical or not. We've had these discussions before, and they lead nowhere. Nobody forces you to install this, and you won't prevent others from doing so. And there are other well-known methods to achieve the same results.

So let's get our hands dirty. This time, the goal is to remove the banner on the home screen for KSO kindles. This won't affect the screensaver, it will simply clean up the home screen. (Update: actually, depending on when you apply the patch, it may also completely disable ads. This is more of an accident than the original intention . See below for details).

I'm writing this as I go, and I have (at this moment) no idea where we are going to end up. The first step is in trying to find out where to begin. We don't really have a starting point yet (and we can't use simple methods like grepping for some unique strings). How about this:

We enable verbose logging on the Kindle, then tap on the banner. Pretty sure there will be some usable hint. Just did that, and while scrolling through a long list of log messages, there is a usable one:

Code:
120510:210921 cvm[6389]: D GestureDispatcher:DebugInfo::GestureDispatcher MousePressed - Source=com.amazon.kindle.home.view.browse.ImageBanner Button=1 Loc=java.awt.Point[x=335,y=57] ForwardTo=null
Time to start looking around in the Java classes!
The ImageBanner class isn't terribly helpful yet. We look through it, seeing that it extends JComponent, and we see some references to com.amazon.kindle.ad.AdUnit (another interesting class name). So much for now. Let's see where ImageBanner is used:

Code:
~/kindle-touch/java/classes$ grep -r ImageBanner .
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/ImageBanner$1.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/ImageBanner.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/ImageBanner$BoundedImage.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/ImageBanner$ViewAdDetailsAction.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/AdPanel.class.
~/kindle-touch/java/classes$ grep -r AdPanel .
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/e.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/AdPanel.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/q.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/c/h.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/c/i.class.
We immediately see that the only use is from AdPanel, so we directly proceed to grepping for that as well. Decompiling AdPanel, we see that the q and e classes are actually inner classes of AdPanel. But there are two interesting things: AdPanel extends com.amazon.kindle.apps.content.view.ContentTable, and it takes an AdManager as a constructor argument. Off we go to AdManager... and we see that it's an interface. Time for another grep:

Code:
~/kindle-touch/java/classes$ grep -r AdManager .
Übereinstimmungen in Binärdatei ./com/amazon/kindle/ad/manager/AdDisplayStrategy.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/ad/manager/AdManager.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/booklet/ad/controller/AdDisplayController.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/booklet/ad/action/ViewAdDetailsAction.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/b/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/a/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/searchresults/q.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/archive/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/c/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/BrowseContentCell.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/n.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/BrowseDisplayController$BrowseMenuManager.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/browse/u.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/view/d/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/e.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/controller/AdPanel.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/c/t.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/c/x.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/home/HomeBooklet.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/controller/q.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/manager/e.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/manager/q.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/manager/a.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/manager/i.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/manager/AdManagerImpl.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/todo/j.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/todo/AdPackageToDoHandler.class.
Übereinstimmungen in Binärdatei ./com/amazon/kindle/restricted/ad/todo/AdResetToDoHandler.class.
Bingo! We see that HomeBooklet references AdManager somehow, so that's our next target. Retrospectively, yes... we could also have started at the HomeBooklet right away.

Now wee see a few things related to ads, like the A() and H() methods, where the booklet registers itself as an AdEventListener, and most notably the method D(AdEvent) implementing that interface. So how about... we make this method do nothing?

Let's try it. The first step is to write a "skeleton patch", which does not include the MD5 sum or any functionality, and to deploy it to the device. This serves to make sure that the patch is considered, and to find out the required MD5 at the same time. This procedure is exactly as in the other HOWTO.

Then we try to (only) replace the AdEventListener interface by removing the entire code therein, except for the return statement:
Code:
		BCMethod m = clazz.getDeclaredMethod("D", new String[] {"com.amazon.kindle.ad.event.AdEvent"});
		Code c = m.getCode(false);
		c.beforeFirst();
		for (int i=0; i < 35; ++i) {
			c.next();
			c.remove();
		}
		c.calculateMaxLocals();
		c.calculateMaxStack();
Copying the patch and restarting the framework shows that the result is: nothing. It still looks as before. So that was obviously the wrong method to try. Remembering something from before, let's go back to that ImageBanner. Remember that it's simply a JComponent. So... how about if we make the ImageBanner "disappear"? We could override the existing getPreferredSize() method to always return (0,0), and the paintComponent() method to do nothing.

The approach is again very similar as above, and the code is checked in, so you can study the source if you want. The result is: yep, the banner is not shown anymore. Mission accomplished? Not really, IMO: something somewhere still seems to think that the banner is shown, and "reserves" the space on the home screen: only 7 items are shown, where there should be 8.

So, one more round, now with the heavy equipment. Let's take a look at AdManager itself (or actually, its implementation, namely com.amazon.kindle.restricted.ad.manager.AdManagerI mpl). I'll let you poke around in it a bit. Even though it's obfuscated, it is relatively straightforward to find that the method m() is a crucial one. It returns a boolean indicating whether the device is ad-activated. Applying the same procedure again, we patch the code to always return false (again, refer to the source code for how it's implemented).

And voilà: After a reboot, the home screen is fully usable, and the ads have disappeared. In fact, while I only wanted to remove them from the home screen, but keep them for the screensaver, there is another effect of this patch: If you activate the patch before you register your Kindle with Amazon (or if you remove /var/local/adunits in whichever way you please, either manually or through a factory reset), no ads will be downloaded anymore.

Note that the above text was essentially a "log" of what I did. The entire procedure took about two hours (including writing this text). I have ended up in some dead end streets (and documented it), and I have written some code which is no longer required. In fact, only the last of the 3 approaches is needed. Code for the other 2 is still kept in the source code, but it's not "active" in the patch. The procedure, as always, involves a bit of intuition. This time we were lucky, because at least most of the class names were still making sense, which helps with the intuition. But even if the framework was fully obfuscated, we would have ended up where we wanted to go, sooner or later.

Anyway, here is the source code, and the binary is attached. Install as usual (i.e.: unzip, copy the .jbpatch file to opt/jbpatch, and insert a line with the file name into CONFIG.TXT).

UPDATE: There is a more recent version !

Last edited by ixtab; 07-25-2012 at 08:26 PM.
ixtab is offline   Reply With Quote