Jump to content

[Question] Change VID/PID while connected


juanchoc

Recommended Posts

Hi everyone,

I'm trying my ducky on a Macbook Pro, and my initial intention was to use it with the composite firmware (to execute the payload while im "looking for a pdf in my pendrive" basically), but i've found some issues along the way.

If i set the VID/PID to the internal keyboard ones (using a non-composite firmware), it works as expected.

If i put the VID/PID of another keyboard, the OS asks me to press a few keys in the new keyboad to confirm it's "allowed" to work.

If i use the composite firmware (using one of the composite VID/PID) it detects the storage device correctly, and the keyboard correctly, but it shows me the same window requesting me to do a few specific keypresess to confirm the new keyboard is secure.

One way to solve this would be to add to my ducky script the initial keypresses required by the OSX keyboard validation screen.

But also while thinking about it, i came across another idea.

Would it be possible to change the VID/PID while the ducky is connected (maybe forcing a disconect/reset so that the host detects the device again, but this time with another VID/PID set)?

One possible use case would be to connect the ducky, it first acts as trusted host keyboard (ie. the internal macbook pro keyboard in my case), executes the payload, and afterwards, triggered by something (the ducky's button? or maybe the end of the script execution?), it swaps the vidpid.bin (ie. with another one that has the vid/pid of a storage device) and forces a reset on the usb device.

Do you think doing something like that would be possible?

Link to comment
Share on other sites

You only need to complete the keyboard wizard once per machine, so I guess it depends where you are using the device?

Have you tried the specifically the VID/PID of a Mac keyboard when in composite mode?

I think it is possible to reset the Ducky. You would have to look at the C++-Code (Firmware), and code a reset procedure, that will reset the Ducky's USB stack, given a certain signal (eg the GPIO button).

Link to comment
Share on other sites

Hi midnitesnake!

Thanks for the fast response!

I've tried using the VID/PID of the internal mac keyboard (and also some of the external mac keyboards) in composite mode, but it didnt recognize the keyboard at all, just the storage drive.

That was a bit odd, because i was expecting it to recognize only the keyboard (since that is the VID/PID i was using) and not the other way around.

Anyway, thanks for the info, i'll look into the firmware code and post back my results!

Link to comment
Share on other sites

There is a function in udc.c called usd_reset(), This may be what you are looking for. Am interested in this idea, so am poking around.

/**
 * \brief Reset the current configuration of the USB device,
 * This routines can be called by UDD when a RESET on the USB line occurs.
 */
void udc_reset(void)

The following code controls the push button, am not quite sure what debounce does yet.

            if( gpio_get_pin_value(GPIO_JOYSTICK_PUSH) == GPIO_JOYSTICK_PUSH_PRESSED ) {
    
                // debounce
                if( debounce == 0 ) {
                    state = state_START_INJECT;
                    debounce = 250;
                }            
            }   
Link to comment
Share on other sites

Then you use an electronic switch the signal maybe 111111111111, when you only pushed the button once not X-times, "debounce" eliminates the extra false positive signals, so the code is only execute once instead of many.

Link to comment
Share on other sites

Thanks overwraith!

I've been looking into the different firmwares, and the avr drivers/framework.

From what i've seen, it seems the udc_reset(void) method resets the configuration of all the device interfaces.

To reset the usb stack, i think i would need to do something like this:

if( gpio_get_pin_value(GPIO_JOYSTICK_PUSH) == GPIO_JOYSTICK_PUSH_PRESSED ) {
   udc_detach();
   udc_stop();

   // Maybe i need to do a udc_reset() here

   // Change VID/PID

   udc_start();
   udc_attach();
   // debounce 
      if( debounce == 0 ) 
      {
         state = state_START_INJECT; debounce = 250; 
      } 
}
Edited by juanchoc
Link to comment
Share on other sites

The code needs to go inside the debounce if statement, like so:

if( gpio_get_pin_value(GPIO_JOYSTICK_PUSH) == GPIO_JOYSTICK_PUSH_PRESSED ) {

    //debounce
    if( debounce == 0 )
    {
        udc_detach();
        udc_stop();

        // Maybe i need to do a udc_reset() here

        // Change VID/PID
        udc_start();
        udc_attach();
        state = state_START_INJECT; debounce = 250;
    }
}

Also, I sent Midnight snake some mail concerning this, the vid/pid code is his, so he has to be the one to give it to you if he does. If the antivirus companies get the vid/pid code we may have to get creative.

I plugged some of this into a composite duck variant, and now I have to figure out why the USB drive isn't mounting after the button is pressed.

Edited by overwraith
Link to comment
Share on other sites

I also put all this junk from the main of the script in the code, and that seems to have solved my USB drive not mounting issue. Don't even really know what this stuff does. Will have to investigate.

        if( gpio_get_pin_value(GPIO_JOYSTICK_PUSH) == GPIO_JOYSTICK_PUSH_PRESSED ) {
            
            // debounce
            if( debounce == 0 ) {
                //reset usb stack
                
                udc_detach();
                udc_stop();
                
                // Change VID/PID
                
                //Junk begin
                irq_initialize_vectors();
                cpu_irq_enable();

                // Initialize the sleep manager
                sleepmgr_init();

                sysclk_init();
                board_init();
                ui_init();
                ui_powerdown();

                memories_initialization(FOSC0);
                //Junk end
                
                udc_reset();
                udc_start();
                udc_attach();
                
                state = state_START_INJECT;
                
                a=0;
                debounce = 100;
            }
        }

Also, I am doing a composite duck variant, so you're solution may be different from mine.

Link to comment
Share on other sites

overwraith:

Awesome! I've reached the same conclusion you did (adding the "junk" in the debounce if).

I refactored the junk part into another function and after executing udc_attach() i also run sleepmgr_enter_sleep().

midnitesnake:

Super awesome midnitesnake! Just what i was looking for. I'll check the code later today and see what i come up with.

Thank you both!

Link to comment
Share on other sites

Ok, I was incorrect about the vid/pid code being secret, it is on the SVN. Here is what my code looks like. So far just making it switch to another vidpid file, but we could possibly make this code read from a space delimited binary file, and thereby choose a random vid/pid. If my other program I am writing pans out we will soon be able to generate this file from the text file I have on the ducky decode website.

		if( gpio_get_pin_value(GPIO_JOYSTICK_PUSH) == GPIO_JOYSTICK_PUSH_PRESSED ) {
			
			// debounce
			if( debounce == 0 ) {
				//reset usb stack
				
				udc_detach();
				udc_stop();
				
				// Change VID/PID
				nav_reset();
				if( nav_setcwd( vidpidFile2, false, false ) ) {
					file_open(FOPEN_MODE_R);
					file_bof();
					
					//vid and pid are uint16_t
					vid =  file_getc() | (file_getc() << 8);
					pid =  file_getc() | (file_getc() << 8);
					
					udc_device_desc.idVendor = (vid);
					udc_device_desc.idProduct = (pid);
					file_close();
				}
				
				//Junk begin
				irq_initialize_vectors();
				cpu_irq_enable();

				// Initialize the sleep manager
				sleepmgr_init();

				sysclk_init();
				board_init();
				ui_init();
				ui_powerdown();

				memories_initialization(FOSC0);
				//Junk end
				
				udc_reset();
				udc_start();
				udc_attach();
				
				state = state_START_INJECT;
				
				a=0;
				debounce = 100;
			}
		}

One more thing, wouldn't sleepmgr_enter_sleep() make the ducky go to sleep? Surely we don't want that?

Edited by overwraith
Link to comment
Share on other sites

overwraith:

One more thing, wouldn't sleepmgr_enter_sleep() make the ducky go to sleep? Surely we don't want that?

From what i understand (http://asf.atmel.com/docs/3.0.1/xmegaa/html/group__sleepmgr__group.html) calling sleepmgr_enter_sleep() makes the ducky go to sleep at the deepest level of sleep allowed.

But the key is where you call that function. I think that if you call it from the main loop, the device would go into sleep but still handle the interrupts (which is all we currently care about).

Also, if you read/write you should call udi_msc_process_trans() to process the read/write operations, and if there's none (false returned) then put the device to sleep.

Eg. (taken from the source of the composite duck firmware):

while (true) {
   if (main_msc_enable) {
      if (!udi_msc_process_trans()) {
         sleepmgr_enter_sleep();
      }
   }else{
      sleepmgr_enter_sleep();
   }
}

In the implementation im working on, instead of using the GPIO button to trigger the change in vid/pid, i'm doing it when the payload execution is complete, and i've been thinking that i could use the GPIO button to execute the payload again (change vid/pid -> execute payload -> change vid/pid again to mass storage).

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...