The essence of the problem
The Xerox 3220 MFP supports network scanning through a Network Scan application installed on one of the computers on the network in which this MFP is registered by IP address. But once the production need required to use VPN connections on this computer (Cisco VPN Client and OpenVPN). And at the moment of connecting any of the connections, the connection with the scanner from the application was instantly lost. My research process and solution of this problem will continue.
First look
Immediately, the thought about the default gateways being replaced, the potential wrapping of all traffic in the VPN, is rejected as inoperative, since All this is not in any of the connections used. The web-interface of the scanner is still available, in the end, it is corny. Then to me, as a network engineer in the first place, it became interesting how the scanner is detected on the network.
For this, I used Wireshark, running it without a VPN connection on the local network interface. Found that the application sends a broadcast udp packet to port 1124, to which the scanner responds. Now we connect VPN and there is complete silence on the local interface, no outgoing packets.
And what's inside?
Well, it is obvious that for some reason the program starts sending packets to the wrong interface, and there, of course, no one responds to it. How to fix it, I was completely incomprehensible, because if the application were guided by the routing table along with the address of the scanner, or something else sane, then everything should have been fine, but this was not the case. So, you need to at least understand the interface selection algorithm, and I decided to implement it using OllyDbg.
Having launched NSCSysUI_XEROX.exe under the debugger (the network scanning application itself, which included a number of * .dll), I, as expected, did not understand anything, because although this is not my first reverse engineering experience, but the previous ones were not particularly successful.

Detection of the scanner clearly occurred, including after pressing the “Refresh” button, and I noticed that in OllyDbg at this moment some kind of debug string output occurs. The last message was just about how the selected IP address of the interface:

For this line of "Selected IP NIC" I decided to catch on. I tried to search for it immediately through Search For - All referenced strings, but there it did not turn out, which made me somewhat depressed and a long F7 from the entry point into the .exe file. As a result, it turned out that it was not at all surprising that there was no line where I was looking for it, since This debug output belongs to a call from NSCProtocol_XEROX.dll, in which that line is already successfully located, and, hooray, this is the procedure with a message:
003B737D |. FF75 DC PUSH DWORD PTR SS:[EBP-24] ; /<%s> 003B7380 |. 8D45 F0 LEA EAX,[EBP-10] ; | 003B7383 |. C645 FC 12 MOV BYTE PTR SS:[EBP-4],12 ; | 003B7387 |. 68 04A13D00 PUSH OFFSET 003DA104 ; |Format = "Selected NIC IP : %s" 003B738C |. 50 PUSH EAX ; |Arg1 003B738D |. E8 D6F70000 CALL 003C6B68 ; \NSCProtocol_XEROX.003C6B68
But this is still not interesting, we are looking for what is there at all in this procedure. First of all, the eye caught on it in calling the function gethostbyname (), which, as MSDN tells us, also returns the entire list of IP addresses by the specified symbolic name.
003B6FCA |. 50 PUSH EAX ; /Arg1, EAX 003B6FCB |. E8 1EF70000 CALL <JMP.&WSOCK32.
Comments speak for themselves. Seeing such a strange application logic, I thought that here it is the key - the program simply uses the first of the array of IP addresses, and for the rest it just runs for nothing. This confidence was supported by the test call gethostbyname (), in the returned structure of which, in the array of addresses, the IP address of the VPN connection always appeared in the first place. And here I had two solutions. The first is to write a bootloader that would intercept gethostbyname () for the specified process and return, or put in the first place the desired IP address. But since I once did this, it was not sporty, and I decided to try the second - patch dll at least at a primitive level.
I replaced the entire specified piece of code with something that in my opinion more corresponded to my case (although I must admit, it is no different from the approach of the application) and drove the only call (assuming that it is some extremely useful) that participates in the above code Only at the first IP address, but for all those encountered:
003B6FD6 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ; IP 003B6FD9 8B00 MOV EAX,DWORD PTR DS:[EAX] ; IP 003B6FDB 33DB XOR EBX,EBX 003B6FDD FF30 PUSH DWORD PTR DS:[EAX] 003B6FDF E8 04F70000 CALL <JMP.&WSOCK32.
What, according to my assumptions, was to force the application to choose not the first IP address, but the last one. Well, or all at once.
However, in the behavior of the application it did not change anything at all. This outcome was also hinted that the output of that debug line used a memory area in which writing had not even occurred. Well, look further.
')
Moment of truth
Then I went down a little lower in the listing, and I saw a call to GetAdaptersInfo (), followed by a loop on quite a few lines, which seemed to be trying to go through each record from the list returned by the function. I meditated on this code for 2 days. And I still haven’t completely understood the logic, but my version is this: the first record is taken, it is checked for the type of interface, non-zero IP address, and the length of the character representation (? This is the most mysterious test for me) of the gateway default for this interface. If the type is appropriate, the address is and the symbolic representation of the gateway is not zero, then we exit the loop and, it turns out, this adapter is selected. And here is the nuance. For my VPN connection, there is no default gateway at all, but the C ++ test call GetAdaptersInfo () with MSDN code does not return it as a missing value, but as “0.0.0.0”, respectively, the length is not zero, and this interface in all respects fits And since He is the first in the list, then he is selected.
Here I was completely sad, and I did not understand how to fix this code for correct operation. But you just need to carefully read the documentation. The function description says:
The GetAdaptersInfo function can retrieve information only for IPv4 addresses.
It can be controlled from the network folder.
If you, like me (and I come across windows administration starting from win2000 server), have never seen this menu before, then this is where it is in Win7:

Where, of course, I saw that all my VPN adapters are above the local network connection, moving it to the very top, I solved the original problem.
PS But still, developers from Xerox could send test requests to all interfaces, and not just to the first available one.