Base Conversions and Creating GUI Apps in PowerShell
I don't know about you, but I find myself doing conversions from decimal to hex and binary several times per day. For me, working out binary equivalents of decimal numbers is something I do all the time to verify subnet masks, network and broadcast addresses - also in answering "is this IP in the same subnet or in an adjacent network?" Conversions of the same type crop up all the time in decoding constructs in packets. Wireshark and Burp will both often anticipate what you want to do on this score, but not always.
Anyway, this all started with a twitter conversation with Lee Holmes - he said that he hasn't used Windows Calc since Powershell got "grown up" math, I said that I used calc all the time for binary <-> decimal all the time, especially if I'm on a client server (and don't have my trusty HP 35s or 16c calculator or emulator handy). Of course, immediately after that conversation I started coding :-)
First of all ,there are more than a few ways to do base conversion in Powershell. I'll start with the obligatory shout out to the Windows PowerShell Cookbook (I'll never get tired of O'Reilly books) - oddly enough Lee is the author of that book!
https://www.amazon.com/gp/product/B00ARN9MEK/ref=dbs_a_def_rwt_hsch_vapi_tkin_p1_i0
specifically this set of "recipes" at http://powershellcookbook.com/recipe/VoMp/convert-numbers-between-bases
The main thing to remember though is that a number is a number, and how you print it is up to you. If you actually want to *store* a number in a different base, you need to convert it to a string value and store the string.
So to convert a number to a different base:
$result = [Convert]::ToString($Number,$BaseToConvertTo) |
If you are starting with a string value in decimal, you'll want to convert it to an integer first:
$result = [Convert]::ToString([int]$NumberAsAString,$BaseToConvertTo) |
Or if you are starting from some other base, you'll want to convert back. A handy shortcut, PowerShell understands that "0x4E" is a hex 4E - we'll use that to convert from Hex number in a string to Decimal:
[Convert]::ToString("0x"+$hexnum, 10) or, an even simpler approach (thanks Lee!): $decnum = [int]("0x"+$hexnum) |
or Binary to Decimal:
$decnum = [convert]::toint32($binnum,2) |
Note that I converted to int32 in this case, since printing a number by default will be in decimal.
Binary to hex:
Convert to $decnum above, then convert dec to hex:
$hexnum = [convert]::tostring($decnum,16) |
So fun all around, but these don't tend to roll off your fingers like using a calculator does (especially if that calculator is RPN). Anyway, this got me to thinking about writing an actual app in Powershell, and looking at GUI support in the native language. Yes, PowerShell does Windows!
Some snips below illustrate various windowing features. First, a screenshot of the app to refer to:
The input box is where we input the starting value:
############################################## text box - INPUT $TextInputBox = New-Object System.Windows.Forms.TextBox $TextInputBox.Location = New-Object System.Drawing.Size(20,50) $TextInputBox.Size = New-Object System.Drawing.Size(300,150) $TextInputBox.Height = 150 $TextInputBox.font = New-Object System.Drawing.Font("Lucida Console",32,[System.Drawing.FontStyle]::Regular) $Form.Controls.Add($TextInputBox) |
Radio buttons are easy to code up too - I use these to select the source base of the number we just typed in. Note that we're setting the size of the box that the buttons live in as a "group box". Sizes are all defined, and the fonts and font size are as well. This code all works as-is on a 4k screen, I haven't tried it at other resolutions (please let me know if it works without tinkering on different res screens?):
############################################## group boxes $groupBox = New-Object System.Windows.Forms.GroupBox $groupBox.Location = New-Object System.Drawing.Size(350,20) $groupBox.size = New-Object System.Drawing.Size(500,400) $groupBox.text = "Source Base" $groupbox.font = New-Object System.Drawing.Font("Lucida Console",16,[System.Drawing.FontStyle]::Regular) $Form.Controls.Add($groupBox) ############################################## ############################################## radio buttons $RadioButton1 = New-Object System.Windows.Forms.RadioButton $RadioButton1.Location = new-object System.Drawing.Point(15,50) $RadioButton1.size = New-Object System.Drawing.Size(800,70) $RadioButton1.Checked = $true $RadioButton1.Text = "Decimal (0d)" $groupBox.Controls.Add($RadioButton1)
$RadioButton2 = New-Object System.Windows.Forms.RadioButton $RadioButton2.Location = new-object System.Drawing.Point(15,130) $RadioButton2.size = New-Object System.Drawing.Size(800,70) $RadioButton2.Text = "Hexadecimal (0x)" $groupBox.Controls.Add($RadioButton2) |
The "GO" button takes the values entered and sends it off to be converted in every-which format in a function:
############################################## GO button $Button = New-Object System.Windows.Forms.Button $Button.Location = New-Object System.Drawing.Size(100,150) $Button.Size = New-Object System.Drawing.Size(220,70) $Button.Font = New-Object System.Drawing.Font("Lucida Console",16,[System.Drawing.FontStyle]::Regular) $Button.Text = "CONVERT" $Button.Add_Click({SrcBase $TextInputBox.Text}) $Form.Controls.Add($Button) |
Finally, outputting the number to an output box is easy too. First create the output box:
############################################## text fields - OUTPUT $outputBox = New-Object System.Windows.Forms.TextBox $outputBox.Location = New-Object System.Drawing.Size(100,475) $outputBox.Size = New-Object System.Drawing.Size(1000,300) $outputBox.MultiLine = $True $outputBox.Font = New-Object System.Drawing.Font("Lucida Console",32,[System.Drawing.FontStyle]::Regular) $Form.Controls.Add($outputBox) |
Then calculate what goes into it (the "GO" function), then output the result:
$NL = "`r`n" $TAB="`t" $result = $NL+"BIN (0b)"+$TAB + $binnum +$NL+"HEX (0x)"+$TAB + $hexnum+$NL+ "DEC (0d)"+$TAB+ $decnum $outputBox.AppendText($result) |
Just for fun, I added ASCII conversions too:
decimal to ascii: [char][int]$decnum
ascii to decimal can be more fun - first convert it to a list of numbers:
$list = [int[]][char[]]$asciistring
Then in a loop convert each list number to hex or binary string representation:
$d = $list[$i]
$h = [convert]::tostring($d,16)
$b = [convert]::tostring($d,2)
The ASCII conversion will convert a string-to-values (yes you can use longer strings, but you'll need to scroll to see the results), but values-to-strings is a single unicode character proposition (so the input values are 0-65535 or 0x0000 -0xFFFF)
As in most GUI apps, this is more or less 20 lines of code and 150-ish lines of formatting, I/O, and yes, input validation - I do check if the value input is valid for the source base.
What I haven't tackled correctly yet is screen resolution. At the moment this little app all hard-coded for a 4k screen, so it's not going to render all that well on other resolutions, especially with lower pixel counts. The better approach would be to set all of the size and position numbers to variables, and get the screen resolution during startup.
For a single screen, that's easy - WMI is your go-to:
(Get-WmiObject -Class Win32_VideoController) | select CurrentHorizontalResolution,CurrentVerticalResolution CurrentHorizontalResolution CurrentVerticalResolution --------------------------- ------------------------- 3840 2160 |
This is a bit more involved for a multiple screen system:
Add-Type -AssemblyName System.Windows.Forms [System.Windows.Forms.Screen]::AllScreens.workingarea | select width,height Width Height ----- ------ 3840 2080 3840 2080 3840 2080 |
With this information in hand, the plan is to change each size / position number to a list of values, so that you can then set a "$res" variable to then use as an index to each list to get the right value for the current screen.
As with everything I post, the source for this is in my github, at https://github.com/robvandenbrink
Got a neat idea that a GUI app in Powershell would be just the ticket for? Or better yet, a link to your github for one that you've written? Please, share using our comment form! If it's an idea that appeals, it might become a future post!
Want to dig deeper into PowerShell with a security focus? Check out SANS SEC505 - you can take it online at the SANSFIRE conference, which is virtual this year ( https://www.sans.org/event/sansfire-2020/course/securing-windows-with-powershell ). If you've taken SEC505 before, re-read the current description, it looks like there's a ton of new content!
===============
Rob VandenBrink
www.coherentsecurity.com
Comments