Monday, 13 June 2016

on Leave a Comment

How to Enable TLS

Image result for tls 1.2 images
In an effort to provide the highest level of security , the connection to Online Banking from devices using any Transport Layer Security (TLS) less than 1.1 is disabled. Any device that is not using TLS 1.1 or higher will not be able to connect to Online Banking. Today, all recent versions of the major internet browsers provide the option to use TLS 1.1 & higher. 

2. Exactly what browsers/versions will provide the option for TLS 1.1 and higher? 

The Online Banking requirements document state that the previous three versions of the browsers listed below are certified and tested for use with Online Banking. Only the last two versions of the Safari browser are certified. These browser versions will support the option to use TLS 1.1 and higher, regardless of what operating system they are used on. Below is a list of the browsers and versions that are certified for use on our Online Banking and support TLS 1.1 & higher. 


Browser Versions 


Internet Explorer 9, 10 & 11 Chrome 41, 42 & 43 Firefox 36, 37 & 38 Opera 27, 28 & 29 Safari 7 & 8 3. 

Are there older versions of operating systems/ browser combinations that will not support TLS 1.1 & higher? 

Yes. Windows XP and Windows Vista are only capable of upgrading up to Internet Explorer version 8. Therefore, users of these operating systems using Internet Explore as their browser will not be able to connect to our Online Banking. However, they would have the option of loading the latest version of another browser such as Chrome* or Firefox. *Chrome has announced that they will end new updates for Windows XP as of April 2015. Enabling SSL Versions TLS 1.1 & TLS 1.2 

Please select the browser that you are using to connect to NetBranch: 

Internet Explorer: 

1. Open Internet Explorer 
2. Click Alt T and select “Internet Options”. 
3. Select the "Advanced" tab. 
4. Scroll down to the "Security" section. 
5. Locate and check "Use TLS 1.1 and TLS 1.2". 
6. Then, press the "OK" button. 

Google Chrome: 


1. Open Google Chrome 
2. Click Alt F and select “Settings”. 
3. Scroll down and select “Show advanced settings…” 
4. Scroll down to the Network section and click on “Change proxy settings…” 
5. Select the "Advanced" tab. 
6. Scroll down to the "Security" section. 
7. Locate and check "Use TLS 1.1 and TLS 1.2". 
8. Then, press the "OK" button. 

FireFox:

1. Open FireFox 
2. Type in “about:config” in the URL bar and press Enter 
3. Scroll down to “security.tls.version.max” and press enter 
4. Set the value to 3 5. Then, press the "OK" button. 

Opera: 


1. Open Opera 
2. Click Ctrl+F12 
3. Click on “Security” 
4. Click on “Security Protocols…” 
5. Check on “Enable TLS 1.1 & TLS 1.2” 
6. Press the "OK" button. 
7. Then, press the "OK" button. 

Safari: 


1. There are no options for enabling SSL protocols. If you are using Safari version 7 or greater, TLS 1.1 & 1.2 are automatically enabled. 

Troubleshooting 


The following steps will aid in determining the issue you may have with connecting to Online Banking as it relates to this change:

 a) Check if TLS 1.1 & 1.2 has been enabled in your browser settings. 

Please see the attached document titled – Instructions for enabling TLS 1.1 & TLS 1.2 for instructions on how to enable these options. 

b) If these options are enabled and you still cannot connect, go to https://www.howsmyssl.com and verify what is showing in the Version section on this page. If you see verbiage similar to what is below and you verified that you have enabled the TLS 1.1 & TLS 1.2 options in the previous step, this could be an indication of an issue with your machine such as a virus or malware. You will need to troubleshoot whatever issue is causing your machine to not have the ability to make the appropriate changes. 
Until the “Version” listed when visiting https://www.howsmyssl.com reports “Good” you will be unable to connect to Online Banking from this machine. 

Suggestions for troubleshooting may include: 

Check if you have current antivirus and/or malware protection 

1. If “yes” then verify the definitions are current and to run a scan. After any issues have been corrected, try https://www.howsmyssl.com” to verify if the version now shows “Good”, if it does then proceed to verify they can access Online Banking. 

2. If “no” consider evaluating some of the programs available, some of which are free. Once current virus/malware scans have run and any issues have been corrected to try the site https://www.howsmyssl.com to verify if the version now shows “Good”, if it does then proceed to verify if you can access Online Banking. 

You also may want to seek local computer repair, if necessary, to determine what is causing your computer to not report “good” even though they have TLS1.1 and TLS 1.2 options enabled c) If the results of https://www.howsmyssl.com show that TLS 1.1 or 1.2 is enabled – similar to the verbiage below, and you still cannot connect to NetBranch, you will need to call Member Services at 791-7070 ext. 3503 for further research Problems connecting directly to Online Banking using your mobile device? Online Banking is not certified for connecting to mobile devices. As stated in the Online Banking requirements document, the only devices certified for access to Online Banking are Windows and Apple/Macintosh PC’s and Laptops.

Tuesday, 7 June 2016

on Leave a Comment

Instant File Initialisation : Impact during Setup

Recently, Erin Stellato (@erinstellato) blogged about the performance impact Instant File Initialization (IFI) can have when creating or restoring databases. She explains that SQL Server 2016 setup now offers you the ability to grant the appropriate rights to the SQL Server service during installation (we also talked about this in the CTP 3.0 section of Latest Builds of SQL Server 2016):


Now you can enable Instant File Initialization during SQL Server setup

The key is a new option (which you can also specify in a configuration file):
SQLSVCINSTANTFILEINIT="True|False"

It's nice that you can really reduce the amount of time it takes to create or restore databases later, without having to remember to go into gpedit, assign the rights correctly, and restart the service. But a much bigger benefit to me is the ability to configure larger tempdb files during setup, taking early advantage of IFI.

Now, there are some limits during setup; for example, the number of tempdb files is limited to 8 (or the number of cores, whichever is less), and the size of each file can only reach a max of 1,024 MB. These limits are enforced in the UI, and I thought that I might be able to get around them by specifying higher sizes in a configuration file for an unattended install, but that didn't work either. (The logs said: "The value 8192 for the TempDB file size exceeds 1024 MB and may have impact to installation time. You can set it to a smaller size and change it after installation.") Personally, I think that in this day and age, with the speed and size of the storage we can obtain, a 1 GB cap on data file size is artificially low. So I filed a Connect suggestion:


And then it was pointed out that Brent Ozar (@BrentO) filed a similar item earlier in the CTP cycle, when the limit was actually enforced as 256 MB instead of 1 GB:


I don't have any monster machines that could support 64 x 1 GB files, and that wouldn't be a realistic test either, so I resolved to testing the impact of IFI on 8 tempdb data files of 1 GB each. I'm kind of old school, so I built four different .ini files, and I've highlighted the lines I would change for each test (I wanted to baseline a minimal install with the 4 x 8 MB data files, using IFI and not, and then compare it to 8 x 1,024 MB files). Since I would be running these loops multiple times, it was important to use different instance names depending on whether IFI was enabled or not, because once you grant the right to a service account, it doesn't get taken away by simply removing the instance (and I could have set those accounts up independently, but I wanted to make these tests easy to reproduce).
;SQL Server 2016 RC0 Configuration File

[OPTIONS]
ACTION="Install"
ENU="True"
QUIET="True"
QUIETSIMPLE="False"
UpdateEnabled="False"
ERRORREPORTING="False"
USEMICROSOFTUPDATE="False"
FEATURES=SQLENGINE
HELP="False"
INDICATEPROGRESS="False"
INSTALLSHAREDDIR="C:\Program Files\Microsoft SQL Server"
INSTALLSHAREDWOWDIR="C:\Program Files (x86)\Microsoft SQL Server"
INSTANCENAME="ABTESTIFI_ON"
INSTANCEID="ABTESTIFI_ON"
SQLTELSVCSTARTUPTYPE="Disabled"
INSTANCEDIR="C:\Program Files\Microsoft SQL Server"
AGTSVCACCOUNT="NT Authority\System"
AGTSVCSTARTUPTYPE="Manual"
SQLSVCSTARTUPTYPE="Manual"
SQLCOLLATION="SQL_Latin1_General_CP1_CI_AS"
SQLSVCACCOUNT="NT Service\MSSQL$ABTESTIFI_ON"
;True for IFI = ON, False for OFF:
SQLSVCINSTANTFILEINIT="False"
SQLSYSADMINACCOUNTS="NT Authority\System"
SQLTEMPDBFILECOUNT="8"
;1024 for 8 GB total, 8 for 64 MB total:
SQLTEMPDBFILESIZE="1024"
SQLTEMPDBFILEGROWTH="64"
SQLTEMPDBLOGFILESIZE="8"
SQLTEMPDBLOGFILEGROWTH="64"
BROWSERSVCSTARTUPTYPE="Manual"

And here is the batch file I used (placed in the same folder as the config files), which installed and then uninstalled the instance using each combination three times, and logged the setup times to a text file – ignoring uninstall and cleanup.

echo Beginning test…
@echo off 2>nul
setlocal enabledelayedexpansion
set outputfile=time.txt
echo. > %outputfile%
rem Remove Eight and/or Sixteen if you only have 4 cores!
FOR %%e IN (Baseline Four Eight Sixteen) DO (
FOR %%x IN (IFI_ON IFI_OFF) DO (
FOR /L %%A IN (1,1,3) DO (
echo INSERT #x VALUES('%%e', '%%x', '!TIME!', >> %outputfile%
D:\setup.exe /Q /IACCEPTSQLSERVERLICENSETERMS /ConfigurationFile=%%e_%%x.ini
echo '!TIME!' ^) >> %outputfile%
D:\setup.exe /Q /ACTION=UNINSTALL /INSTANCENAME=ABTEST%%x /FEATURES=SQL
rem del /Q /S "C:\Program Files\Microsoft SQL Server\MSSQL13.ABTEST%%x\*.*"
rem rd /Q /S "C:\Program Files\Microsoft SQL Server\MSSQL13.ABTEST%%x\"
)
)
)
@echo on
echo …test complete.

A few notes:
  • You may need to change the two lines from D:\setup.exe to the path to the setup directory.
  • You may need to restart your system before running this.
  • You'll want to run the batch file from an elevated command prompt so that UAC doesn't interrupt you on every iteration.

I ran tests on three different systems:

A Windows 10 VM with 4 cores and SSD storage
Baseline test of 4 x 8MB and then 4 x 1,024 MB
A Windows 10 VM with 8 cores and PCIe storage
Baseline test of 4 x 8MB, 4 x 1,024 MB, 8 x 1,024 MB
A Windows 2012 R2 VM with 16 cores and a dual-channel RAID 10 array of 8 10K SAS drives
Baseline test of 4 x 8MB, 4 x 1,024 MB, 8 x 1,024 MB, and 16 x 1,024 MB

The output files generated a bunch of insert statements I could paste here:

CREATE TABLE #x ( [server] varchar(32), [test] varchar(32), [start] time(2), [end] time(2) ); -- inserts pasted here SELECT [server],[test],AVG(DATEDIFF(SECOND,[start],[end])*1.0) FROM #x GROUP BY [server],[test];


Here were the timings across ten tests each, averaged and rounded (click to enlarge):

Predictably, IFI becomes important with larger files on slower drives

Setup takes a little over a minute across the board (how nice it is to run setup without Management Tools). The only deviation, really, was when the file sizes started to get bigger on the mechanical drives and with instant file initialization disabled. I can't pretend to be shocked by this.
Conclusion

If you are on SSD or PCIe, instant file initialization can't make things worse, but there is no clear benefit during setup, as long as the archaic file size limitations for tempdb data files remain intact. With the current rules it doesn't seem possible to test this impact beyond (1 GB x the number of cores available). If you are on slow mechanical drives, though, there is a noticeable difference, even when only initializing 8 GB or 16 GB of data – that zeroing out is rather expensive when the disk heads have to move. That said, whether setup takes 75 seconds or 2 minutes is pretty inconsequential in the grand scheme of things (unless you're installing hundreds of servers, but not automating that for some reason), so I think the bigger advantage here is convenience – not having to remember to go grant the service account the volume rights necessary some time after installation has succeeded. If you think about it, this new configuration option can actually pay off much better in automated installs of large numbers of servers, outside of any time saved during the actual installation.
on Leave a Comment

SQL Support for TLS 1.2


Updated 

At the end of January, Microsoft announced that TLS 1.2 would now be supported in specific builds of SQL Server 2008, 2008 R2, 2012, and 2014. Personally, I was pleasantly surprised to see this support back-ported to 2008 and 2008 R2; I was convinced that those customers would just be urged to upgrade if TLS coverage was that important to them. So this is great news.
Before you rush out and deploy, though, there are a few issues you should be aware of.
  • UPDATE March 2, 2016 – if you were looking for the downloads to apply to 2008 or 2008 R2 after February 13th, you would have only found the patches for SQL Native Client (they have "SNAC" in the name). This was because the patches were pulled due to an issue involving sporadic service termination. This issue has been addressed, and the downloads have now been restored. Here is what had been posted on the official release services blog post on February 13th:
    Update: February 13, 2016: We have two customers that have reported unexpected service terminations for SQL Server 2008 and SQL Server 2008 R2 after installing the above updates. We are actively working on investigating the reported issues. Although the service terminations have not been conclusively correlated to this update, till the root cause is identified we are being proactive and disabling the downloads for both SQL Server 2008 and SQL Server 2008 R2. If you have an affected environment, please uninstall the installed update.
    Today, this update appeared, so it appears safe to go back into the water:
    Update: March 2, 2016: […] The following SQL Server database engine versions are affected by the intermittent service termination issue that is reported in KB3146034. For customers to protect themselves from the service termination issue, we recommend that they install the TLS 1.2 updates for Microsoft SQL Server that are mentioned in this article if their SQL Server version is listed in the following table.
    [For x86 and x64, the post lists 10.0.6543 and 10.50.6537. IA-64 builds are also listed.]
  • UPDATE February 22, 2016 – If you are running SQL Server 2014 and are on a CU path, new Cumulative Updates have been released for both RTM and SP1 that address the encrypted endpoint issues mentioned in KB #3135852.
  • UPDATE February 18, 2016 – If you are running SQL Server 2008 or 2008 R2, a problem has surfaced after the application of the latest updates. As a result, the downloads for those versions have been pulled, and a fix is being investigated. I missed an update to
  • If you are running SQL Server 2014, using encrypted endpoints for Availability Groups, Database Mirroring, or Service Broker, and are not eligible for the GDR updates (in other words, you are already at a build higher than 12.0.4219 for SP1 or 12.0.2271 for RTM), you should not rush out and deploy TLS 1.2. There is a known issue reported in KB #3135852 – for the CU branches of SQL Server 2014, this issue has been addressed in RTM CU #12 and SP1 CU #5 (see this post for more details). The Knowledge Base article doesn't currently address this point, because changes to KBs have a lot of red tape (the blog post has been updated to warn about this issue).
  • You might find that SQL Server Agent will not start after enabling only TLS 1.2. The fix, according to Amit Banerjee, is to install the updated SQL Server Native Client drivers for your operating system from KB #3135244. You should do that anyway.
  • Management Studio and other client tools might be unable to connect. Amit Banerjee (again!) tells us that the fix is to install the proper .NET framework hotfix, again from KB #3135244. You should do that anyway.
  • If you are trying to get IIS and SQL Server to communicate using only TLS 1.2 on the same box, you might have to abandon that plan and move IIS, at least according to this answer on dba.stackexchange (he also left some details on this post).
  • To avoid most of these issues, just update SQL Server Native Client, ODBC/JDBC, and .NET Framework hotfixes on all clients that will ever come into contact with SQL Server instances where TLS 1.2 is enabled. Or on all machines period. Again, you can get these fixes from KB #3135244.

Decision Matrix

It seems straightforward, but as of today, not all builds will enable you to rush out and convert to TLS 1.2 exclusively. Here is what I suggest for each set of builds (in addition to patching .NET Framework, SQL Server Native Client, ODBC, and JDBC on all machines):
SQL Server 2014 Service Pack 1
12.0.4416 => 12.0.4438You are on a CU path. You should apply Cumulative Update #5.
12.0.4050 => 12.0.4218You are on SP1 RTM or the SP1 GDR path. For full support now, install the SP1 GDR TLS 1.2 Update (12.0.4219). Though I would opt for Cumulative Update #5, and deploy that instead, especially if the encrypted endpoint issue above might affect you.
SQL Server 2014 RTM
12.0.2546 => 12.0.2563You are on a CU path. You should apply Cumulative Update #12.
12.0.2342 => 12.0.2545You are on a CU path but no TLS 1.2 support. You could add that support if you move to a later CU (CU #8, #9, #10, #11, or #12); I would recommend Cumulative Update #12.
12.0.2000 => 12.0.2270You are on RTM or the RTM GDR path. For full support now, install the RTM GDR TLS 1.2 Update (12.0.2271). Though I would opt for Cumulative Update #12, and deploy that instead, especially if the encrypted endpoint issue above might affect you.
SQL Server 2012 Service Pack 3
11.0.6216 => 11.0.6518You have full support for TLS 1.2.
11.0.6020 => 11.0.6215Here, you have a choice; you can install the SP3 GDR TLS 1.2 Update(11.0.6216) or apply SP3 Cumulative Update #1 (11.0.6518). I prefer the cumulative update, personally, especially given Microsoft's new stance on CUs and the fact that you'll get more fixes for the same level of regression testing.
SQL Server 2012 Service Pack 2
11.0.5644 => 11.0.5644You have full support for TLS 1.2.
11.0.5353 => 11.0.5643For full support, apply SP2 Cumulative Update #10 (11.0.5644).
11.0.5058 => 11.0.5351Here, you have a choice; you can install the SP2 GDR TLS 1.2 Update, when it is published again (11.0.5352), or apply SP2 Cumulative Update #10 (11.0.5644). I prefer the cumulative update, personally, especially given Microsoft's new stance on CUs and the fact that you'll get more fixes for the same level of regression testing.
SQL Server 2012 RTM & Service Pack 1
11.0.2100 => 11.0.5057Your only choice for TLS 1.2 support is to move to Service Pack 2 or, preferably,Service Pack 3, and then apply the TLS update.
SQL Server 2008 R2 Service Pack 3
10.50.6000 => 10.50.6541For full support, apply the SP3 TLS 1.2 Update (10.50.6542).
SQL Server 2008 R2 RTM, Service Pack 1, and Service Pack 2
10.50.1600 => 10.50.5999Your only choice for TLS 1.2 support is to move to Service Pack 3 and then apply the TLS update.
SQL Server 2008 Service Pack 4
10.0.6000 => 10.0.6546For full support, apply SP4 TLS 1.2 Update (10.0.6547).
SQL Server 2008 RTM, Service Pack 1, Service Pack 2, and Service Pack 3
10.0.1600 => 10.0.5999Your only choice for TLS 1.2 support is to move to Service Pack 4 and then apply the TLS update.

Tuesday, 31 May 2016

on Leave a Comment

Reverse Engineer Any Software



Reverse engineering, the process of taking a software program’s binary code and recreating it so as to trace it back to the original source code, is being widely used in computer hardware and software to enhance product features or fix certain bugs. For example, the programmer writes the code in a high-level language such as C, C++ etc. (you can learn basic C programming with this beginners course); as computers do not speak these languages, the code written in these programming languages needs to be assembled in a format that is machine specific. In short, the code written in high level language needs to be interpreted into low level or machine language.

The process of converting the code written in high level language into a low level language without changing the original program is known as reverse engineering. It’s similar to disassembling the parts of a vehicle to understand the basic functioning of the machine and internal parts etc. and thereafter making appropriate adjustments to give rise to a better performing or superior vehicle.

If we have a look at the subject of reverse engineering in the context of software engineering, we will find that it is the practice of analyzing the software system to extract the actual design and implementation information. A typical reverse engineering scenario would comprise of a software module that has been worked on for years and carries the line of business in its code; but the original source code might be lost, leaving the developers only with the binary code. In such a case, reverse engineering skills would be used by software engineers to detect probable virus and malware to eventually protect the intellectual property of the company. 


At the turn of the century, when the software world was hit by the technology crisis Y2K, programmers weren’t equipped with reverse engineering skills. Since then, research has been carried out to analyse what kind of development activities can be brought under the category of reverse engineering so that they can be taught to the programmers. Researchers have revealed that reverse engineering basically comes under two categories-software development and software testing. A number of reverse engineering exercises have been developed since then in this regard to provide baseline education in reversing the machine code.

Reverse Engineering

Reverse engineering can be applied to several aspects of the software and hardware development activities to convey different meanings. In general, it is defined as the process of creating representations of systems at a higher level of abstraction and understanding the basic working principle and structure of the systems under study. With the help of reverse engineering, the software system that is under consideration can be examined thoroughly. There are two types of reverse engineering; in the first type, the source code is available, but high-level aspects of the program are no longer available. The efforts that are made to discover the source code for the software that is being developed is known as reverse engineering. In the second case, the source code for the software is no longer available; here, the process of discovering the possible source code is known as reverse engineering. To avoid copyright infringement, reverse engineering makes use of a technique called clean room design.


In the world of reverse engineering, we often hear about black box testing. Even though the tester has an API, their ultimate goal is to find the bugs by hitting the product hard from outside. 

Apart from this, the main purpose of reverse engineering is to audit the security, remove the copy protection, customize the embedded systems, and include additional features without spending much and other similar activities.

Where is Reverse Engineering Used?

Reverse engineering is used in a variety of fields such as software design, software testing, programming etc. 
In software design, reverse engineering enables the developer or programmer to add new features to the existing software with or without knowing the source code. Different techniques are used to incorporate new features into the existing software. 
Reverse engineering is also very beneficial in software testing, as most of the virus programmers don’t leave behind instructions on how they wrote the code, what they have set out to accomplish etc. Reverse engineering helps the testers to study the virus and other malware code. The field of software testing, while very extensive, is also interesting and requires vast experience to study and analyze virus code. 
The third category where reverse engineering is widely used is in software security. Reverse engineering techniques are used to make sure that the system does not have any major vulnerabilities and security flaws. The main purpose of reverse engineering is to make the system robust so as to protect it from spywares and hackers. Infact, this can be taken a step forward to Ethical hacking, whereby you try to hack your own system to identify vulnerabilities. 


While one needs a vast amount of knowledge to become a successful reverse engineer, he or she can definitely have a lucrative career in this field by starting off with the basics. It is highly suggested that you first become familiar with assembly level language and gain significant amount of practical knowledge in the field of software designing and testing to become a successful software engineer. 

Reverse Engineering Tools

As mentioned above, reverse engineering is the process of analyzing the software to determine its components and their relationships. The process of reverse engineering is accomplished by making use of some tools that are categorized into debuggers or disassemblers, hex editors, monitoring and decompile tools: 

  • Disassemblers – A disassembler is used to convert binary code into assembly code and also used to extract strings, imported and exported functions, libraries etc. The disassemblers convert the machine language into a user-friendly format. There are different dissemblers that specialize in certain things. 
  • Debuggers – This tool expands the functionality of a disassembler by supporting the CPU registers, the hex duping of the program, view of stack etc. Using debuggers, the programmers can set breakpoints and edit the assembly code at run time. Debuggers analyse the binary in a similar way as the disassemblers and allow the reverser to step through the code by running one line at a time to investigate the results. 
  • Hex Editors – These editors allow the binary to be viewed in the editor and change it as per the requirements of the software. There are different types of hex editors available that are used for different functions. 
  • PE and Resource Viewer – The binary code is designed to run on a windows based machine and has a very specific data which tells how to set up and initialise a program. All the programs that run on windows should have a portable executable that supports the DLLs the program needs to borrow from. 


Reverse engineering has developed significantly and taken a positive approach to creating descriptive data set of the original object. Today, there are numerous legitimate applications of reverse engineering. Due to the development of numerous digitising devices, reverse engineering software enables programmers to manipulate the data into a useful form. The kind of applications in which reverse engineering is used ranges from mechanical to digital, each with its own advantages and applications. Reverse engineering is also beneficial for business owners as they can incorporate advanced features into their software to meet the demands of the growing markets.

Tuesday, 17 May 2016

on Leave a Comment

Dynamic Menu Builder

The problem

As with every abstraction it starts with a problem you are trying to solve. In this case the problem was code duplication and general tediousness with the construction of the context (right click) menus in x64dbg.

The general idea of Qt is great. From my understanding, every context menu is a QMenu with a bunch of QAction or other QMenu items in it. When a user right-clicks in the widget a signal will be emitted and the widget can connect to the signal, construct the QMenu and ‘execute’ the menu on the mouse position. Each QAction has a signal called triggered() which you can connect to a slot in your widget to handle the click event.

If there is no variation in the menu everything works perfectly fine. You just create all the actions, menus and connections in the constructor and store the final QMenu item in the class. Then when you need the menu you do mMenu->exec(position) and you are done with it.

In x64dbg the menus are based on the context, so the static approach doesn’t work. What we did was create and connect all the QAction items in the constructor and then dynamically create the menu. What this did was create a lot of fragmentation. All the actions had to be declared in the header, the slots for the actions had to be declared in the header and the source and adding a new action would result in a lot of code that looked exactly like this:
mFollowAddress = new QAction("&Follow in Disassembler", this); connect(mFollowAddress, SIGNAL(triggered()), this, SLOT(followAddress())); 


For actions with a shortcut and an icon it was even worse:

mToggleBreakpoint = new QAction("Toggle Breakpoint", this); mToggleBreakpoint->setShortcutContext(Qt::WidgetShortcut); mToggleBreakpoint->setIcon(QIcon(":/images/icons/breakpoint.png")); addAction(mToggleBreakpoint); connect(mToggleBreakpoint, SIGNAL(triggered()), this, SLOT(toggleBreakpoint())); 


Shortcuts also require setting the actual shortcut in a dedicated slot called refreshShortcutsSlot()which is connected to the settings dialog so shortcuts are updated when the user updates the settings:

void ReferenceView::refreshShortcutsSlot() { mToggleBreakpoint->setShortcut(ConfigShortcut("ActionToggleBreakpoint")); mToggleBookmark->setShortcut(ConfigShortcut("ActionToggleBookmark")); } 


Finally the menu is created in contextMenuEvent like this:

if(!DbgMemIsValidReadPtr(addr)) return; wMenu->addAction(mFollowAddress); wMenu->addAction(mFollowDumpAddress); if(apiAddressFromString(mCurList->getCellContent(mCurList->getInitialSelection(), 1))) wMenu->addAction(mFollowApiAddress); wMenu->addSeparator(); wMenu->addAction(mToggleBreakpoint); wMenu->addAction(mToggleBookmark); 


As you can imagine, adding an action with an icon, a shortcut and some context-dependent behaviour was a very tedious process and this needed to change.
MenuBuilder

Part of the solution is a MenuBuilder class. This is a recursive datatype (like QMenu) but it lazily builds the menu, which allows for proper context-awareness.

To achieve context-awareness, each QAction/QMenu/MenuBuilder you add to a MenuBuilder is paired with an std::function. If the callback returns true, the item is added to the final QMenu, otherwise it is ommitted. This allows for constructs like this:
mBuilder->addAction(followAction, [this](QMenu* menu) { //only add followAction if the selected address is readable. return DbgMemIsValidReadPtr(this->selectedAddress()); }); 


The followAction will only be added to the final QMenu if the currently selected address is a valid memory address. This is a huge save in code, the menu creation slot can be replaced with:
QMenu menu; mBuilder->build(&menu); menu.exec(pos); 


There are some extra features (like using the menu parameter of the lambda to add extra actions to the final QMenu, but if you want more details, read the code here.

Actions

The next problem to solve is the creation of the QAction and QMenu items. The solution was to create a few simple helper methods in the base class (AbstractTableView):

template<typename T> inline QAction* makeAction(const QString & text, T slot) { return connectAction(new QAction(text, this), slot); } inline QAction* connectAction(QAction* action, const char* slot) { connect(action, SIGNAL(triggered(bool)), this, slot); return action; } inline QAction* connectAction(QAction* action, QActionLambda::TriggerCallback callback) { auto lambda = new QActionLambda(action->parent(), callback); connect(action, SIGNAL(triggered(bool)), lambda, SLOT(triggeredSlot())); return action; } 


The makeAction uses a template because I added lambda support to the actions. This is not in Qt 4 and rather simple to implemented so I decided to add it:

class QActionLambda : public QObject { Q_OBJECT public: typedef std::function<void()> TriggerCallback; QActionLambda(QObject* parent, TriggerCallback callback) : QObject(parent), _callback(callback) { } public slots: void triggeredSlot() { if(_callback) _callback(); } private: TriggerCallback _callback; }; 


Now to create an action you’d write:

makeAction("Selection (&No Bytes)", SLOT(copySelectionNoBytesSlot())) 


And similarly an action with shortcut and icon:

makeShortcutAction(QIcon(":/icons/images/highlight.png"), "&Highlighting mode", SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode") 

Final words

I guess that’s about it for this blog post. If you want to see what the final menu creation code looks like, check out the code here. For reference, the old code is available here, as you can tell it is a great improvement.