Run the Windows Command Prompt in Full Screen

Have you ever wanted to run the windows command prompt but realize that for some reason Microsoft has limited it to be at most 80 characters wide? Well, there is a way to bypass that limitation. After opening the command prompt run the Windows Management Instrumentation Command-line by issuing the command: wmic. Then make the cmd window full screen or resize it to the desired size. Then exit wmic by using the exit command. you shoudl now be in the Windows command prompt with a windows of whatever size you desire!

The sequences of commands should look like this:

cmd
wmic
[resize window now]
exit

I have tested, and can confirm that this works on both Windows XP and Windows 7.


The Great Blog Reboot of 2012

Hello World 2.0!

I have (reluctantly) made the decision to migrate my blog from my custom made PHP CMS to WordPress. While I like the customizability, flexibility, and lightweightness of my own CMS, I was getting to a point where I wanted new abilities and was too interested working on other more interesting projects to code them. So, I migrated to WordPress. All posts previous to this one where from my old blog, which can still be found HERE.


LDAP Authentication for Cakephp

This article is going to help you using LDAP to authenticate users rather than relying on a users table with a password column. I will be assuming you will be using cakephp 1.3 and that you have completed Auth and/or ACL setup on your application similar to the ACL tutorial on the cakephp book.

Because we want to control the logging in of the user ourselves and not leave it to the cake magic we need to override the auth component. To do this copy your auth.php from your CAKE_CORE/controllers/components/ to your APP/controllers/components/ folder. Next open it up and fine the login function. It should be around like 684. Once you find it comment out everything inside the fucntion (but leave the function intact. It should look something like this:

function login($data = null) {
    /*$this->__setDefaults();
    $this->_loggedIn = false;
    if (empty($data)) {$data = $this->data; }
    if ($user = $this->identify($data))
    { $this->Session->write($this->sessionKey, $user);
    $this->_loggedIn = true; }
return $this->_loggedIn;*/ }

Next open up your users controller and find your login function. Assuming you followed the guide or have implemented some basic auth you should have an empty login function.

I have written a LDAP helper that can easily be included as a LIB for Cakephp that will get some user data and validate the login, copy and paste it from below to APP/libs/ldap.php

<?php
class ldap{

    private $ldap = null;
    private $ldapServer = 'AD.domain.com';
    private $ldapPort = '389';
    public $suffix = '@domain.com';
    public $baseDN = 'dc=domain,dc=com';
    private $ldapUser = 'LDAPUser';
    private $ldapPassword = 'Pas5w0rd';

    public function  __construct() {
        $this->ldap = ldap_connect($this->ldapServer,$this->ldapPort);

        //these next two lines are required for windows server 03
        ldap_set_option($this->ldap, LDAP_OPT_REFERRALS, 0);
        ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
    }

    public function auth($user,$pass)
    {
        if (empty($user) or empty($pass))
        {
            return false;
        }
        @$good = ldap_bind($this->ldap,$user.$this->suffix,$pass);
        if( $good === true ){
            return true;
        }else{
            return false;
        }
    }

    public function __destruct(){
        ldap_unbind($this->ldap);
    }

    public function getInfo($user){
        $username = $user.$this->suffix;;
        $attributes = array('givenName','sn','mail','samaccountname','memberof');
        $filter = "(userPrincipalName=$username)";

        ldap_bind($this->ldap,$this->ldapUser.$this->suffix,$this->ldapPassword);
        $result = ldap_search($this->ldap, $this->baseDN, $filter,$attributes);
        $entries = ldap_get_entries($this->ldap, $result);

        return $this->formatInfo($entries);
    }

    private function formatInfo($array){
        $info = array();
        $info['first_name'] = $array[0]['givenname'][0];
        $info['last_name'] = $array[0]['sn'][0];
        $info['name'] = $info['first_name'] .' '. $info['last_name'];
        $info['email'] = $array[0]['mail'][0];
        $info['user'] = $array[0]['samaccountname'][0];
        $info['groups'] = $this->groups($array[0]['memberof']);

        return $info;
    }

    private function groups($array)
    {
        $groups = array();
        $tmp = array();

        foreach( $array as $entry )
        {
            $tmp = array_merge($tmp,explode(',',$entry));
        }

        foreach($tmp as $value) {
            if( substr($value,0,2) == 'CN' ){
                $groups[] = substr($value,3);
            }
        }

        return $groups;
    }
}
?>

Edit the variables at the tom of the file to reflect your setup.

Now we are going to make our Users->login function check the POST username and password against LDAP, and then if valid it will preform the login magic that auth used to do.

Fill your login function with this:

    function login() {
        App::import('Lib', 'ldap');
        if ($this->Session->read('Auth.User')) {
             $this->redirect(array('controller' => 'allocations', 'action' => 'index'));
        } elseif (!empty($this->data)) {
            $ldap = new ldap;
            if ($ldap->auth($this->Auth->data['User']['user'], $this->Auth->data['User']['password'])) {

                $userrow = $this->User->findByUsername($this->data['User']['user']);
                if (!$userrow) {
                    $ldap_info = $ldap->getInfo($this->data['User']['user']);
                    $this->data['User']['username'] = $this->data['User']['user'];
                    $this->data['User']['name'] = $ldap_info['name'];
                    $this->data['User']['group_id'] = 3; //sets the default group
                    $this->add();
                    $userrow = $this->User->findByUsername($this->data['User']['user']);
                }

                $user = $userrow['User'];

                $this->Auth->Session->write($this->Auth->sessionKey, $user);
                $this->Auth->_loggedIn = true;

                $this->Session->setFlash('You are logged in!');
                $this->redirect(array('controller' => 'allocations', 'action' => 'index'));
            } else {
                $this->Session->setFlash(__('Login Failed', true));
            }
        }
    }

To quickly summarize, it first checks to see if the user is logged in, if not, and post data is provided it will check the provided credentials with the LDAP Lib. If valid it then attempts to get the user from the users table, if the user does not exist it creates it with information provided from LDAP and defaults set in the function.

I built this to still work with a users table to allow relationships between other models and users. but it can be used without a users table, just remove the if(!$userrow) statement and the line before it.

NOTE: If you use a users table, you do not need, and should not have, a password column.

That should be it! You should now be using LDAP for user credential validation.


Picture Frame Tablet PC

Backstory

A few years ago when the local Circuit City was going out of business I decided to stop by to see if there where any good deals. Unfortunately most of their inventory was at a very low discount (if at all). However they where getting rid of some of their CRM and sales equipment. I picked up a 3M touch-panel LCD monitor for $20 or so, sold “as-is”. When I got home I realized that the LCD panel was only 800x600px, and had a broken back-light. I tried to get the touch panel working but for some reason it was not receiving power and I could not find any drivers for it. Into storage it went.

A few months later I dusted it off and decided to give it another try. I was able to find a way of providing 5v power to the controller board for the touch panel, and after much searching I found the drivers.

3M microtouch touchpanel

The Hardware

Once I got the driver, power to the board, and figured out its serial connection it was surprisingly easy to get working. Below you can see a picture and video of the touch panel wired up and working on a laptop.

touch panel wired to laptop

The next step was to remove the glass touch panel from the broken LCD. The glass was only held on by some very strong adhesive. After carefully removing it I tested it to make sure everything was still in good working order.

Testing the touchpanel on a laptopHello World on the touch panel

Now is when the fun starts! I picked up a picture frame that used a piece of glass the exact same size of the touch panel from a local arts and crafts store. I also found a old Pentium M laptop I would be modifying to use the touch panel on its screen with the picture frame.

Below you can see the touch panel in the picture-frame, and the laptop I would be using for this project with its screen removed and the touch-panel attached by its side.

Touch-panel in picture frametouch panel on laptop

I gutted the laptop of unneeded parts, such as the keyboard, mouse, DVD drive, and lots of other plastic bits that would be in the way or covered up. Then I reattached its screen backwards, so that when it folds down it faces up.

Laptop with backwards screen on hingelaptop with screen reversedlaptop with screen on backtesting the laptop with the touch panel again

I mounted the touch panel’s controller board where the DVD drive once was, and gave it 5v of power from the laptop’s USB ports. Below you can see the picture-frame resting on the laptop but not attached yet, and the wiring for the touch-panel.

picture frame on laptopTouch panel resting on laptop, not well connected yet/

Now for the inside wiring!

using USB for 5c DCInside of touch panel lapopusing hot gluelook at how nice it looks...

As you can see I used hot glue to hold the controller board in the optical drive bay. And all the wiring was looking good. I just needed a way to mount the touch-panel/picture frame to the rest of the laptop.

And here was my solution:

back of picture frame touch pca metal bracket

I would use these bent metal brackets I picked up at home depot to secure them together.

brackets being appliedEverything mounted

At this point everything was working great. I should probably mention what those blue wires are that you can see sticking out of it. They lead to the laptop’s power and standby buttons. Those buttons would normally be located right above the keyboard, however with this mod they are no longer assessable, so they will be relocated.

picture frame tablet pcpower and standby buttons

I mounted the power and standby buttons (seen above) on a piece of plastic from the LCD assembly. I placed it over the hole in the laptop where the outside of the DVD drive was.

This concludes the hardware portion of this mod.

the finished picture frame tablet pc

The Software

To make the interface more touch friendly I installed RockerDock to make launching application nicer.

Also since there is no longer a keyboard I used the Touch-It Virtual Keaboard to replace key input. I like this keyboard because it can hide easily and not take up any screen real estate when you need it.

If anyone reading this needs the driver for their 3M MT7 touch panel, or If I ever need the link for the driver, here is that too: http://solutions.3m.com/wps/portal/3M/en_US/TouchSystems/TouchScreen/CustomerSupport/TouchScreenDrivers/

In addition to the utilities above, I also Installed XBMC, which acts as a perfect picture displaying software. and with UPNP/DNLA I can control it from my phone, and even wirelessly display photos from my phone on it via my network.

If you want to see higher resolution copies of any of the photos in this article check out the Picasa gallery for it HERE.


Logitech Revue Unboxing

Google was nice enough to provide me with a free Google TV as part of their 10,000 free Google TVs for developers. Below is the unboxing, see the item descriptions.


IMAG0039.jpg

The Unopened box

IMAG0040.jpg

Back of the box

IMAG0042.jpg

Removing the top of the box relieves the keyboard.

IMAG0043.jpg

Removing the keyboard shows you the actual Revue itself.

IMAG0044.jpg

All of the contents of the Logitech Revue boxRevue, Keyboard/mouse, HDMI cable, Bower cables, IR Blaster, and a welcome card.

IMAG0045.jpg

The IR Blaster.The Revue also has 3 IR blasters built into it.

IMAG0046.jpg

Enjoy!

IMAG0047.jpg

The remote and Revue

IMAG0048.jpg

Rear ports.(from left to right)Pair button, HDMI in, 2x IR out, 2x USB, network, HDMI out, Optical audio out, power.

IMAG0050.jpg

The Application menu

IMAG0051.jpg

The Twitter appVery basic

IMAG0052.jpg

OS Version/Info

IMAG0053.jpg

The Chrome web browser with search

IMAG0054.jpg

;)Yes, this is real.

This device looks promising, However I felt like it was lacking. But when Google Released the android app market for it in 2011 things should be much different. If you watched the entire sideshow you will notice that I already started tinkering with it ;)


PHPRepo

This is about a piece of software I wrote over a year ago to fit a need I had at the time. It probably will not receive any updates but I have released the source to anyone is free to do as they please with it.

Background

PHPRepo is a PHP CMS for managing Debian package repositories. A while ago I wanted to start my own repository for some of my own packages, so I looked for an easy way to do this. I found none. At the time the only way to run and manage a Debian package repository was through apt at the command line, and since at the time I was learning PHP I decided to write my own software to fill this void. Thus I created PHPRepo. PHPRepo has very minimal requirements and can work alongside an existing repository that is managed with apt.

Installation

Installation is as easy as it gets for a PHP app. There are no databases to configure, as it used the Debian repository files as its database. Simply upload the phprepo files to the root of your web-server and edit the config file with a user name and password you wish to use.

Also, if you want the ability to manage the repository in addition to view it in your web browser then make sure the user on your server that the web-server is running under has read and write permission to the repository files.

Screenshot Tour

My screenshots are for a repository that already has a few packages in it. If you are making a repository from scratch you will not be able to see as much.

PHPrepo main screen

Above is the main screen. You can see a tree list structure of all of your repositories, components, and architectures.

PHPrepo repository list

Above you can see the list of all repositorys on the system.

PHPRepo repository detail

Clicking on a repository brings you to the repository page; shown above. It will list all of the packages in the repository.

PHPrepo search

One very nice feature is the ability to search from a web browser.

PHPrepo add upload

If you choose to use PHPRepo to manager your repository, the above screen will allow you to add/upload packages to your repository. Simply select the file, distribution, and component. If the distribution or component that you want does not exist you can create it. All details about the package such as name, arch, etc are read from the deb file upon upload. Its like magic!

PHPRepo package view

If you click on a package you will be taken to the screen above. This page lets you view the details of the package. You can also manually downland the deb file, or a Maemo .install file. You can also manage the file by deleting its entry in the repository or by deleting the entry and remove the actual file from the server.

PHPRepo Delete file from repo

If you choose to delete a file you will see the above screen asking if you are sure.

PHPrepo Delete entire repository

The above screen is for deleting an entire repository, and all packages associated with it.

Conclusion

As stated before, I made this program over a year ago to fill a void. And I was rather surprised that nothing like this already existed. In any case the program and its source code can be downloaded from its project hosted at Google Code.

PHPRepo at Google Code


Wifi Radar

This is a highly directional super sensitive 802.11 G Wifi antenna. It was created using a used Direct TV satellite dish, weather proof container, a Hawking high-gain wireless antenna and some scrap parts. It is not a radar, it is just a cool name for this project. ;)

The Idea

The Hawking wireless card/antenna I used in this is already directional, but this gave it even more of a boost.

To get the most gain and to make the antenna the most effective use the parabolic equation to find the location of the focus in both the X and Y directions, this is where you want the wireless antenna to be, so that it will receive the strongest signal from the most angles.

The antenna will be enclosed in a weather proof container I for for free as a sample from OKW Enclosures.

The Construction

I used a rack adapter for some old ethernet switch to attach the enclosure to the end of the direct TV dish.

Container on Direct Tv dishEnclosure on dishweather proof enclosure on dish.

I mounted the wireless card inside the enclosure merely by adding a screw head for it to sit on.

Antenna and top of enclosure Screw head ready for mountingantenna mounted

I added a hole in the back for a usb cable to fit through and then sealed it up with hot-glue. Below you can see the finished product.

Final productCompleted wifi satellite dish with usb cableDish-in-a-box

Results

I used merageek’s inSSIDer 2 to test the gain of the antenna. inSSIDer 2 is a much needed replacement of the old war-driving software network stumbler. Comparing the signal strength of both using my new antenna and not I got about 10db of gain. I was hoping for more but it is still nice. And even with only 10db of gain, I was able to go from picking up 2 wireless networks to at least 20, depending on which way I aimed the antenna.

I would also like to mention another piece of software called Ekahau HeatMapper. While this software is not useful with this antenna design it can be useful making out signal strength of a building or neighborhood. Its fun to play with.


Android WiFi Sniffing

Android devices, while unable to put their wireless cards into monitor mode, can still be used to sniff wireless traffic. they are just limited to traffic that goes through them. So to get data to pass through your android device other than its own data we need to have it act as a rogue access point. A rogue access point is an AP that you will control and have your “clients” or *cough”victims*cough* connect to. android 2.2 has this ability to act as a mobile hotspot built in, 2.1 and earlier version will need Wireless Tether for Root Users. I actually prefer the 3rd party app the Android’s built in ability as it offers many more features. And in case this was not obvious from the start, you will need root to preform anything in this article.

The trick to make clients connect to your rogue AP is how you name it, If you are at *bucks then naming it “*bucks free wifi” might be a good idea, however *bucks and many other WiFi hotspots go through “AT&T’s global WiFi network” which is named “att wifi”, so naming your SSID “att wifi” would be even better, because you will get new conections, and you may even be able to have some existing connections re-conect to you if your signal is stronger, and it probaly will be because you will be near everybody else vs. their AP somewhere in the back room.

Capturing Packets the Easy Way

If you dont want to mother messing around with any command lines then luckaly there are some nice apps that can handle packet capturing for android. First I want to mention Packet Sniffer. Packet Sniffer is a very crude app (and is in desperate need of a GUI overhaul), but is does offer the ability to sniff bluetooth, however I had no luck getting it to work.

The program that I want to praise is Shark for root. Shark utilizes tcpdump to save .pcap files of the traffic going through the phone, and it works flawlessly. the author even wrote Shark Reader to view the .pcap fiels on android, however you will most likely want to view them on Wireshark on a desktop.

Shark Reader File SelectorShark Reader PacketsShark Reader DumpShark Reader header data

Capturing Packets the Fun Way

If you installed Debian using this article, or some other method then you can use many more Linux tools. Once you get the traffic you want going through your phone you can install and run any Debian app you want. I will cover two.

Dsniff

Install:

apt-get install dsniff

Running:

Dsniff Running on Android

In the above screenshot you can see dsniff capturing my username (root) and password (secret) when I logged into my router at 192.168.1.1 (I changed my password since then)

Ettercap

Ettercap is quite a bit more advanced that dsniff, and I will not teach you how to use it in this guide, you can learn more here.

Install:

apt-get install ettercap

Start:

ettercap -C

Ettercap on Android

The -C option starts it in the TUI mode. (Text user interface). Ettercap can do everything dnsiff can, plus more, it was built for man-in-the-middle attacks, much like the one we are doing here with android.

Conclusion

Now that more and more people are getting smartphones, this type of attack is becoming easier to pull off. And with everybody’s wireless devices always looking to connect to the global “linksys” or “NETGEAR” this becomes very practical. Anything that goes unencrypted over the air-waves could potentially be seen by others, even the inconspicuous guy in the corner plating on his phone ;)

And in case this was not obvious form the start, DON’T BE AN IDIOT. This article was written for information purposes, anything stupid you may do with this information is your own doing not mine.

Update 1/04/2012:

Recently there has been an explosion of arp mitm attack type programs for android (all require root) Some good ones are:


Install Debian on Android

This is a minimalistic how-to to get a Debian environment running on almost any (rooted) android phone. I adopted the method here: http://www.saurik.com/id/10 to be more universal and added some new features.

Preparing the Debian Image

You will need access to a computer dunning a Debian based distribution to create the image for you phone. I used Ubuntu 10.04. To create the image you need to install a program called debootstrap. debootstrap will allow you to create a mini Debian install in your image.

After installing debootstrap you will need to create a filesystem image for android to use and for debootstrap to install Debian to. You can use the dd command to create the image. In my example below I made a 800MB image. Once the image is made you need to format it to a Linux file system.

Once your image it formated you should mount it and then run debbootstrap.

Below are my example commands, you may want/need to change them to fit your environment. Such as the Debian mirror, file size, etc.

sudo -s
apt-get install debootstrap
dd if=/dev/zero of=debian.img seek=838860800 bs=1 count=1
mke2fs -F debian.img
mkdir debian
mount -o loop debian.img debian/
debootstrap --verbose --arch armel --foreign lenny debian http://ftp.us.debian.org/debian
umount debian/
rm -r debian/

Prepairing the Debian boot script

Below is my Debian boot script (named bootdebian). I created it off the boot Ubuntu script for the HTC Droid Incredible, but modified it. My script includes the ability to become root if you are not already root, and it will mount your Incredible’s SD card and internal memory inside Debian so that you can easily move files in and out of your Chrooted environment. I also fixed some small errors on the other script. If you are not using the HTC Incredible you will want to change lines 38-47 to reflect your phone’s memory mount points.

EDIT 10/18/10:

Not everybody’s phone will use “/dev/block/mtdblock3″ for the /system mount point. Type the mount command to see what the propper mount point is on your device. The one used in this guide is for the HTC Incredible.

if [[ $EUID -ne 0 ]]
then
echo "Becoming ROOT!"
su -c bootdebian
exit 1
fi

echo "Mounting system as R/W"
mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system

echo "Setting some stuff up.."
export bin=/system/bin
export img=/mnt/sdcard/debian.img
export mnt=/data/local/debian
export PATH=$bin:/usr/bin:/usr/sbin:/bin:$PATH
export TERM=linux
export HOME=/root
if [ ! -d $mnt ]
then
mkdir $mnt
fi

echo "Mounting the Linux Image"
mknod /dev/block/loop5 b 7 0 #may already exist
losetup /dev/block/loop5 $img
mount -t ext2 -o noatime,nodiratime /dev/block/loop5 $mnt
mount -t devpts devpts $mnt/dev/pts
mount -t proc proc $mnt/proc
mount -t sysfs sysfs $mnt/sys

echo "Setting Up Networking"
sysctl -w net.ipv4.ip_forward=1
echo "nameserver 8.8.8.8" &gt; $mnt/etc/resolv.conf
echo "nameserver 8.8.4.4" &gt;&gt; $mnt/etc/resolv.conf
echo "127.0.0.1 localhost" &gt; $mnt/etc/hosts

echo "Mounting sdcard and emmc in /mnt"
if [ ! -d $mnt/mnt/emmc ]
then
mkdir $mnt/mnt/emmc
fi
busybox mount --bind /mnt/emmc/ $mnt/mnt/emmc
if [ ! -d $mnt/mnt/sdcard ]
then
mkdir $mnt/mnt/sdcard
fi
busybox mount --bind /mnt/sdcard/ $mnt/mnt/sdcard

echo "Entering CHROOT "
echo " "
chroot $mnt /bin/bash

echo " "
echo "Shutting down CHROOT"
umount $mnt/mnt/emmc
umount $mnt/mnt/sdcard
sysctl -w net.ipv4.ip_forward=0
umount $mnt/dev/pts
umount $mnt/proc
umount $mnt/sys
umount $mnt
losetup -d /dev/block/loop5
mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system

Now move both the above script and the debian.img file you made to your phone’s memory card.

Finishing up the Image

Now we need to finish up the install on your phone. Upen the terminal app you plan to use on your phone, I recomendConnectBot. First we will re-mount the system partition as Read/Write, them move out bootdebian script over, make it executable, then remove it from the SD card. Then we run the bootdebian script and run the second stage of debootstrap.The second stage of debootstap will take a while, it took me 15 minutes, let it run. Once debootstrap has finished we will add the official Debian repository into the system, then use apt-get to remove the files left over by debootstap. Here are the commands:

su
mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system
cat /sdcard/bootdebian &gt; /system/xbin/bootdebian
rm /sdcard/bootdebian
chmod 777 /system/xbin/bootdebian
bootdebian
/debootstrap/debootstrap --second-stage
echo 'deb http://ftp.us.debian.org/debian lenny main' &gt;/etc/apt/sources.list
apt-get autoclean
apt-get update
exit

You are done!

Now you can run “bootdebian” anytime from your phone’s tereminal to enter a full Debian system. You can apt-get install any Debian package that has been compiled to armel. :)

If you want to go further you can install X, and a VNC server. This would allow you to VNC into the Debian system from your phone giving you a full X enviroment.

Now go enjoy your full Linux distribution on your phone!


HTC Incredible Virtual CD-ROM Hack

The official HTC Incredible 2.2 update added a new feature to the ROM. When the phone is connected to a computer via USB, even if the memory card is not mounted, it will act as a virtual CD-ROM. It basically justs acts as a CR-ROM drive with the disk image found in  /system/etc/CDROM.ISO. The default ISO was some annoying Verizon thing. Most (rooted) users simply deleted the ISO from their system. I however found a way to make this feature a bit more useful.

Enabling and Disabling the CD-ROM the Right Way

The first way most people disabled this was to delete the ISO. This is not the correct way of doing it. Just deleting the file will still have the phone show an empty CD-ROM drive when plugged in to a computer. There is a nice ON/OFF switch for the CD-ROM that can be changed by anyone (non-rooted users) To enable/disable the CD-ROM feature follow these steps:

  1. Dial ##7764726
  2. Press Call
  3. Enter the password 000000 (6 zeros)
  4. Select Feature Settings
  5. Select CD-ROM
  6. Choose Enable or Disable
  7. Press Menu
  8. Select Commit Modifications (Don’t worry if it says no settings changed)
  9. Press Home

Using Your Own ISO

The ISO file that is mounted needs to be named CDROM.ISO in /system/etc/. So, after deleting the default ISO image (via the good old rm command) you can replace it with any ISO image you want. However this will be difficult with large ISOs and it will be a pain to mount system with R/W access and use the command line every time you want to change the ISO. So I propose this alternate solution, use a symbolic link! I made a symbolic link in /system/etc/CDROM.ISO that points to a CDROM.ISO on my internal memory card. To do this run this command as root:

rm /system/etc/CDROM.ISO  (if you have not yet deleted the CD-ROM image)
ln /emmc/CDROM.ISO /system/etc/CDROM.ISO

Replace /emmc/ with /sdcard/ if you want to use your SD card and not the phone’s internal memory.

Finishing Up

Now place a ISO file on either your SD card or internal memory and it should be mounted as a CD-ROM drive. Ill let you be creative with what you could put in there (*cough* auto-run scrips*cough*). Unfortunately I cannot seem to get computers to boot off the ISO using this method. I’m guessing that it is because when the Incredible mounts the ISO it strips the boot flag. Also, since this hack will make the Incredible always access either your internal memory or your SD card, when selecting mount over USB the drive holding the ISO will be busy or in use by the system and sometimes will not mount on the computer. This can be fixed by force unmounting the drive (in your phone’s settings menu) or by temporarily disabling the CD-ROM feature (see above).

To my knowledge this hack only applies to the HTC Incredible with the official 2.2 build or ROMs built off of the official 2.2 build. Please let me know in the comments if this works on any other phones.