Since you haven't provided more information, I am unsure how to best answer. Sadly, the stackexchange system does not allow me to make a comment to your question in which I could clarify these things, due to me not having enough reputation.
So here goes my attempt at giving you some directions, willfully ignoring that you can't modify your routing table (you will understand why reading my suggestion):
Depending on the VPN client and where it hooks into the FIB (forward information base) of the kernel, you might have some luck in that the monitoring of the FIB, or, using your expression routing table, by the VPN only happens for the local and main rule tables. You can check your routing rules using
ip rule show
For each of the strings behind the tag "lookup" (which are the rule table entries), you can query the according routing information from the FIB, using
ip route show table <name>
With a bit of luck you could try to construct a rule that matches your requirements and give it preference in the rule lookup table. For example (I made something up to give you a head-start), let's add a new rule with higher preference than main to certain flows:
ip rule add from 192.168.1.0/24 to 10.10.212.1/30 iif eth0 oif eth2 lookup 888 pref 12000
ip rule show
0: from all lookup local
12000: from 192.168.1.0/24 to 10.10.212.1/30 iif eth0 oif eth2 lookup 888
32766: from all lookup main
32767: from all lookup default
On a standard Linux (Ubuntu in the case of this post) system, you'd be seeing the three default rule tables local, main and default, of which you normally only see the main table when invoking netstat -rn for example.
Now we want to populate the FIB entries in lookup table 888 with a new routing entries:
ip route add default via 10.37.129.4 dev eth2 table 888
Let's see how our routing entries in table 888 look like:
ip route show table 888
default via 10.37.129.4 dev eth2
I think you get the idea. Now, with regard to your specific routing needs, it's unclear as to what exactly you're trying to achieve. Make sure that you flush the routing cache when toying with rule tables:
ip route flush cache
Note, that using the iproute2 architecture you can basically filter and modify virtually any FIB entry; rule entries can even be made based on fwmarks and/or u32 classifiers, like follows (example taken from the policy routing book):
tc filter add dev eth1 parent ffff: protocol ip prio 1 u32 \
match ip src 10.1.1.0/24 classid :1
ip rule add fwmark 1 table 1 prio 15000 realms 3/4
ip route add default via 192.168.1.1 table 1 src 192.168.1.254
ip route flush cache
For things go haywire in rule tables entries, many years ago I had prepared a small bash snippet to put my system back to original routing rules state:
: ${KEEP:="local main default"}
while read prio rule; do
continue=0
for keep in ${KEEP}; do
if [ "${rule//lookup ${keep}/}" != "${rule}" ]; then
continue=1
fi
done
if [ ${continue} -eq 0 ]; then
ip rule del prio ${prio%%:*} ${rule//all/0/0}
fi
done < <(ip rule show)
Surprisingly, it seems that after over 10 years of iproute2's existence, still only few people seem to know that there is an universe beyond classical "broken" tools like ifconfig or netstat.