Saturday, December 19, 2009

AIO Bot Driver

AIO Bot uses a driver (or so they say) for some of their Warden protection.

I'm on an x64 machine and I really cbf setting up a kernel debugger on my XP x86 VM, so for now a static analysis will have to suffice.

They seem to perform a single kernelmode hook, it is on ZwQuerySystemInformation. They use it to hide processes and adjust some processor information.

The former they use because their bot uses a process for its GUI. What they don't seem to have realized is:

  • Warden does NOT scan processes.
  • They got the process names wrong in their hook, so even if Warden was looking for them, their hook wouldn't work. (Lol)
  • There are information codes other than SystemProcessInformation which return the exact same list, but with just a tiny bit of extra information. All of these codes must be handled otherwise their hook can by bypassed. (Good luck finding all of them, most are 100% undocumented and will require reversing of the Windows kernel.)
The latter I have no idea about. I was hoping someone with some more kernelmode experience could shed some light on that.

Overall their driver seems to be very poorly written, and is obviously the work of a complete amateur. I mean, shit, I have very little kernel-mode experience and even I could do a better job than this clusterfuck.

Here is the full dump of their hook sub, cleaned up, named, and documented by Kynox and I.

NTSTATUS __stdcall ZwQuerySystemInformation_Hook(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength)
{
  PVOID pCurrentEntry; // ebx@1
  PVOID pPreviousEntry; // ebp@3
  unsigned int TempIdleTime1; // eax@7
  unsigned __int8 TempIdleTimeFlag1; // cf@7
  unsigned int TempKernelTime1; // eax@7
  unsigned __int8 TempKernelTimeFlag1; // cf@7
  unsigned __int8 TempIdleTimeFlag2; // cf@11
  unsigned __int8 TempKernelTimeFlag2; // cf@11
  int IdleTimeTemp2; // ecx@18
  unsigned __int8 IdleTimeTemp3; // cf@18
  NTSTATUS TrampResult; // [sp+1Ch] [bp+10h]@1

  pCurrentEntry = SystemInformation;
  // Call original API
  TrampResult = ZwQuerySystemInformationTramp(
                  SystemInformationClass,
                  SystemInformation,
                  SystemInformationLength,
                  ReturnLength);
  // Check if original API succeeded
  if ( TrampResult >= 0 )
  {
    // Check for SystemProcessInformation
    if ( SystemInformationClass == 5 )
    {
      pPreviousEntry = 0;
      if ( SystemInformation )
      {
        do
        {
          // Check pCurrent->ImageName.Buffer
          if ( *((_DWORD *)pCurrentEntry + 15) )
          {
            // Check for the presence of a couple of unknown processes.
            // This conditional will always fail because there are no processes used by these names!
            if ( !strncmp(*((const char **)pCurrentEntry + 15), (const char *)L"wow007", 12)
              || !strncmp(*((const char **)pCurrentEntry + 15), (const char *)L"wowmf", 10) )
            {
              // Do something with pCurrentEntry->UniqueProcessId
              sub_11151(*((_DWORD *)pCurrentEntry + 17));
              // Modify pCurrentEntry->IdleTime
              TempIdleTime1 = *((_DWORD *)pCurrentEntry + 10);
              TempIdleTimeFlag1 = TempIdleTime1 >= -(_DWORD)qword_120F8;
              LODWORD(qword_120F8) = TempIdleTime1 + qword_120F8;
              HIDWORD(qword_120F8) += *((_DWORD *)pCurrentEntry + 11) + TempIdleTimeFlag1;
              // Modify pCurrentEntry->KernelTime
              TempKernelTime1 = *((_DWORD *)pCurrentEntry + 12);
              TempKernelTimeFlag1 = TempKernelTime1 >= -(_DWORD)qword_120E8;
              LODWORD(qword_120E8) = TempKernelTime1 + qword_120E8;
              HIDWORD(qword_120E8) += *((_DWORD *)pCurrentEntry + 13) + TempKernelTimeFlag1;
              // Advance to next entry if there are still entries to process
              if ( pPreviousEntry )
              {
                if ( *(_DWORD *)pCurrentEntry )
                  *(_DWORD *)pPreviousEntry += *(_DWORD *)pCurrentEntry;
                else
                  *(_DWORD *)pPreviousEntry = 0;
              }
            }
          }
          else
          {
            // Modify pCurrentEntry->IdleTime and pCurrentEntry->KernelTime even on unnamed processes
            TempIdleTimeFlag2 = (_DWORD)qword_120F8 >= (unsigned int)-*((_DWORD *)pCurrentEntry + 10);
            *((_DWORD *)pCurrentEntry + 10) += qword_120F8;
            *((_DWORD *)pCurrentEntry + 11) += HIDWORD(qword_120F8) + TempIdleTimeFlag2;
            TempKernelTimeFlag2 = (_DWORD)qword_120E8 >= (unsigned int)-*((_DWORD *)pCurrentEntry + 12);
            *((_DWORD *)pCurrentEntry + 12) += qword_120E8;
            *((_DWORD *)pCurrentEntry + 13) += HIDWORD(qword_120E8) + TempKernelTimeFlag2;
            qword_120E8 = 0i64;
            qword_120F8 = 0i64;
          }
          // Advance to next entry if there are still entries to process
          pPreviousEntry = pCurrentEntry;
          if ( *(_DWORD *)pCurrentEntry )
            pCurrentEntry = (char *)pCurrentEntry + *(_DWORD *)pCurrentEntry;
          else
            pCurrentEntry = 0;
        }
        while ( pCurrentEntry );
      }
    }
    else
    {
      // SystemProcessorPerformanceInformation
      if ( SystemInformationClass == 8 )
      {
        // Increase IdleTime
        IdleTimeTemp2 = (unsigned __int64)(qword_120F8 + qword_120E8) >> 32;
        IdleTimeTemp3 = (_DWORD)qword_120F8 + (_DWORD)qword_120E8 >= (unsigned int)-*(_DWORD *)SystemInformation;
        *(_DWORD *)SystemInformation += qword_120F8 + qword_120E8;
        *((_DWORD *)SystemInformation + 1) += IdleTimeTemp2 + IdleTimeTemp3;
      }
    }
  }
  return TrampResult;
}



13 comments:

Volker said...

made my day,thanks :D

Aaron said...

Ya know I guess someone who does this should really decide whether it's worth his time or not. You spend all this time doing this... for a hobby? Seriously? Or do you have some sort of interest in this bot? Or... are you just "doing them a favor"? I am guessing #2.

Your losing money to them. So instead helping them. You simply bitch them out in a "good" sense of the words.

Great job man. You must feel good!!!

Awesome work my man!

Do you sleep at night? Knowing the code for AIO bot is bad code?

Cypher said...

I guess I could ask you the same thing.

Does bitching to someone who couldn't care less what you think make YOU feel good?

I certainly couldn't care less what your opinion of me is, which means you're in the deliciously ironic situation where you're doing EXACTLY what you're complaining about.

Quite funny really.

I do this because I find it fun. I like reverse engineering, I like programming, and I like dealing with anti-cheat systems (especially trying to subvert them).

Life is all about having fun, so if this is what I enjoy, and I choose to spend my time that way, who are you to tell me otherwise?

Do you consider going out and having a good time with friends "losing money" because you're not working? If so I really feel sorry for you, you must have a VERY sad, lonely, and boring life. (Maybe that's why you're so bitter to people like myself?)

It seems to me you're just upset because I've somehow hit a nerve with you (be it because you're financially invested in the bot, because you don't like being told you made a stupid decision, etc).

Sure, I also do this because I'm an asshole and I like to show off, but at least I can admit that.

You on the other hand I'm not so sure about...

Volker said...

Aaron:
i don't know why he does it but i think he just wants to show the world what's really up with the bot.
I mean they are lying to their customers telling them there is no or very little chance of a ban. with those functions hooked even i do know that there is a really good chance to be banned.
They shouldn't lie to their customers and this won't happen...

Cypher said...

That's quite true.

Normally when we see stuff like "does not use injection" and then we also see "works in the background" that raises HUGE red flags. (As it's hard to do both of these things together. Glider was only able to do it because it hooked APIs in the kernel with the use of a driver.)

Honestly it's like a flag to a bull.

If they had said "uses injection" and "currently has no warden protection" then we probably would had left them alone.

However they chose to lie, and hence attracted a lot of unwanted attention. They have no one to blame but themselves.

Brian said...

Good stuff, always find these posts interesting.

Kissy said...

Nowt wrong with what Cypher does, I for one am glad he does it, so what if some people invested in the bot, thats there failed mistake, always wait for someone with the knowlage to give there opinion on the bot. People have more money than sense now adays. If it sounds to good to be true, then it usally is. and Cypher will usaslly prove it

Cypher said...

Well, at any rate, I don't understand all the crying.

I'm HELPING the bot developers. Isn't it better that an independent researcher picks up and reports issues before Blizzard finds them?

Unless of course you're anti-bot and you want to see all the cheaters get banned, at which point you should probably go back to hating me, because I facilitate cheating.

jeremiah said...

"I'm HELPING the bot developers. Isn't it better that an independent researcher picks up and reports issues before Blizzard finds them?"

You're a moron.

Cypher said...

Hahahaha, somebody's butt-hurt. What's wrong? Did I insult your precious bot? It's okay, you can tell me, I promise not to take your lunch money.

clanstyles said...

lol Cypher... Guys there's no reason to even argue with him over this.

He loves doing this, he's NOT going to stop. Fuck, I wouldn't either and if you had 1/2 the knowledge that he had you probably wouldn't either.

Sure I don't know jack shit about reverse engineering, but that doesn't stop me. I still make things in C# and other languages (C++ when approperiate but I can't find shit to make ever).

I mean it's fun and a hobby. Cypher can probably turn it into a carrier, and what's better than doing what you love for the rest of your life. Nothing will stop him.. lol

Just stfu about this.

Besides, it's fucking funny to see how stupid these guys are, GAME GARD woot!

7nmv54rym7 said...

aaron is so cursorily and feeble-minded. it would be better if he would look at his own stuff and dont talk shit if someone is doing something good and from interest

unknowngunman said...

Sorry but Cypher is pretty much one of a few Gods in the botting game. And the EI-EI-O bot boys aren't. If Cypher wanted your money for his bot, you'd give it to him. I know I would. If he says your shit stinks. It does. See he has what's called... clout, when he talks about botting, people listen because he DOESN'T have a history of telling lies and stealing people's money.

Post a Comment